Skip to content

Commit f512812

Browse files
committed
add config + new client for NGTS
This will add initial support for NGTS. Auth is based on the existing Venafi Cloud client using a keypair. Signed-off-by: Ashley Davis <ashley.davis@cyberark.com>
1 parent 0da5d21 commit f512812

File tree

6 files changed

+1092
-77
lines changed

6 files changed

+1092
-77
lines changed

pkg/agent/config.go

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,17 @@ type AgentCmdFlags struct {
178178

179179
// Prometheus (--enable-metrics) enables the Prometheus metrics server.
180180
Prometheus bool
181+
182+
// NGTSMode (--ngts) turns on the NGTS mode. The agent will authenticate
183+
// using key pair authentication and send data to NGTS endpoints.
184+
NGTSMode bool
185+
186+
// TSGID (--tsg-id) is the TSG (Tenant Service Group) ID for NGTS mode.
187+
TSGID string
188+
189+
// NGTSServerURL (--ngts-server-url) is a hidden flag for developers to
190+
// override the NGTS server URL for testing purposes.
191+
NGTSServerURL string
181192
}
182193

183194
func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) {
@@ -330,6 +341,34 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) {
330341
panic(err)
331342
}
332343

344+
c.PersistentFlags().BoolVar(
345+
&cfg.NGTSMode,
346+
"ngts",
347+
false,
348+
"Enables NGTS mode. The agent will authenticate using key pair authentication and send data to NGTS endpoints. "+
349+
"Must be used in conjunction with --tsg-id, --client-id, and --private-key-path.",
350+
)
351+
c.PersistentFlags().StringVar(
352+
&cfg.TSGID,
353+
"tsg-id",
354+
"",
355+
"The TSG (Tenant Service Group) ID for NGTS mode. Required when using --ngts.",
356+
)
357+
358+
ngtsServerURLFlag := "ngts-server-url"
359+
360+
c.PersistentFlags().StringVar(
361+
&cfg.NGTSServerURL,
362+
ngtsServerURLFlag,
363+
"",
364+
"Override the NGTS server URL for testing purposes. This flag is intended for agent development and should not need to be set.",
365+
)
366+
367+
// ngts-server-url is intended only for developers, so hide it from help
368+
if err := c.PersistentFlags().MarkHidden(ngtsServerURLFlag); err != nil {
369+
panic(err)
370+
}
371+
333372
}
334373

335374
// OutputMode controls how the collected data is published.
@@ -343,6 +382,7 @@ const (
343382
VenafiCloudVenafiConnection OutputMode = "Venafi Cloud VenafiConnection"
344383
LocalFile OutputMode = "Local File"
345384
MachineHub OutputMode = "MachineHub"
385+
NGTS OutputMode = "NGTS"
346386
)
347387

348388
// The command-line flags and the config file and some environment variables are
@@ -387,6 +427,10 @@ type CombinedConfig struct {
387427
ExcludeAnnotationKeysRegex []*regexp.Regexp
388428
ExcludeLabelKeysRegex []*regexp.Regexp
389429

430+
// NGTS mode only.
431+
TSGID string
432+
NGTSServerURL string
433+
390434
// Only used for testing purposes.
391435
OutputPath string
392436
InputPath string
@@ -411,6 +455,10 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
411455
keysAndValues []any
412456
)
413457
switch {
458+
case flags.NGTSMode:
459+
mode = NGTS
460+
reason = "--ngts was specified"
461+
keysAndValues = []any{"ngts", true}
414462
case flags.VenafiCloudMode && flags.CredentialsPath != "":
415463
mode = VenafiCloudKeypair
416464
reason = "--venafi-cloud and --credentials-path were specified"
@@ -448,6 +496,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
448496
default:
449497
return CombinedConfig{}, nil, fmt.Errorf("no output mode specified. " +
450498
"To enable one of the output modes, you can:\n" +
499+
" - Use --ngts with --tsg-id, --client-id, and --private-key-path to use the " + string(NGTS) + " mode.\n" +
451500
" - Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the " + string(VenafiCloudKeypair) + " mode.\n" +
452501
" - Use --venafi-connection for the " + string(VenafiCloudVenafiConnection) + " mode.\n" +
453502
" - Use --credentials-file alone if you want to use the " + string(JetstackSecureOAuth) + " mode.\n" +
@@ -463,6 +512,56 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
463512

464513
var errs error
465514

515+
// Validation of NGTS mode requirements.
516+
if res.OutputMode == NGTS {
517+
if flags.TSGID == "" {
518+
errs = multierror.Append(errs, fmt.Errorf("--tsg-id is required when using --ngts"))
519+
}
520+
if flags.ClientID == "" {
521+
errs = multierror.Append(errs, fmt.Errorf("--client-id is required when using --ngts"))
522+
}
523+
if flags.PrivateKeyPath == "" {
524+
errs = multierror.Append(errs, fmt.Errorf("--private-key-path is required when using --ngts"))
525+
}
526+
527+
// Error if MachineHub mode is also enabled
528+
if flags.MachineHubMode {
529+
errs = multierror.Append(errs, fmt.Errorf("--machine-hub cannot be used with --ngts. These are mutually exclusive modes."))
530+
}
531+
532+
// Error if VenafiConnection mode flags are used
533+
if flags.VenConnName != "" {
534+
errs = multierror.Append(errs, fmt.Errorf("--venafi-connection cannot be used with --ngts. Use --client-id and --private-key-path instead."))
535+
}
536+
537+
// Error if Jetstack Secure OAuth mode flags are used
538+
if !flags.VenafiCloudMode && flags.CredentialsPath != "" {
539+
errs = multierror.Append(errs, fmt.Errorf("--credentials-file (for Jetstack Secure OAuth) cannot be used with --ngts. Use --client-id and --private-key-path instead."))
540+
}
541+
542+
// Error if API Token mode is used
543+
if flags.APIToken != "" {
544+
errs = multierror.Append(errs, fmt.Errorf("--api-token cannot be used with --ngts. Use --client-id and --private-key-path instead."))
545+
}
546+
547+
// Error if --venafi-cloud is used with --ngts
548+
if flags.VenafiCloudMode {
549+
errs = multierror.Append(errs, fmt.Errorf("--venafi-cloud cannot be used with --ngts. These are different deployment targets."))
550+
}
551+
552+
// Error if organization_id or cluster_id are set in config (these are for Jetstack Secure / CM-SaaS)
553+
if cfg.OrganizationID != "" {
554+
errs = multierror.Append(errs, fmt.Errorf("organization_id in config file is not supported in NGTS mode. This field is only for Jetstack Secure."))
555+
}
556+
557+
if cfg.ClusterID != "" {
558+
errs = multierror.Append(errs, fmt.Errorf("cluster_id in config file is not supported in NGTS mode. Use cluster_name instead."))
559+
}
560+
561+
res.TSGID = flags.TSGID
562+
res.NGTSServerURL = flags.NGTSServerURL
563+
}
564+
466565
// Validation and defaulting of `server` and the deprecated `endpoint.path`.
467566
{
468567
// Only relevant if using TLSPK backends
@@ -491,15 +590,39 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
491590
// The VenafiCloudVenafiConnection mode doesn't need a server.
492591
server = client.VenafiCloudProdURL
493592
}
593+
if res.OutputMode == NGTS {
594+
// In NGTS mode, use NGTSServerURL if provided, otherwise we'll use a default
595+
// (which will be determined when creating the client)
596+
server = res.NGTSServerURL
597+
}
494598
}
599+
600+
// In NGTS mode: ignore the config-file server field entirely; use only
601+
// --ngts-server-url when provided (default URL is derived from TSG ID
602+
// at client construction time).
603+
if res.OutputMode == NGTS {
604+
if res.NGTSServerURL != "" {
605+
log.Info("Using custom NGTS server URL (for testing)", "url", res.NGTSServerURL)
606+
}
607+
608+
// config-file server field has no impact in NGTS mode so warn about it
609+
if cfg.Server != "" {
610+
log.Info(fmt.Sprintf("ignoring the server field in the config file. In %s mode, use --ngts-server-url for testing.", NGTS))
611+
}
612+
613+
server = res.NGTSServerURL
614+
}
615+
495616
url, urlErr := url.Parse(server)
496-
if urlErr != nil || url.Hostname() == "" {
617+
if server != "" && (urlErr != nil || url.Hostname() == "") {
497618
errs = multierror.Append(errs, fmt.Errorf("server %q is not a valid URL", server))
498619
}
620+
499621
if res.OutputMode == VenafiCloudVenafiConnection && server != "" {
500622
log.Info(fmt.Sprintf("ignoring the server field specified in the config file. In %s mode, this field is not needed.", VenafiCloudVenafiConnection))
501623
server = ""
502624
}
625+
503626
res.Server = server
504627
res.EndpointPath = endpointPath
505628
}
@@ -530,6 +653,12 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
530653
log.Info(fmt.Sprintf(`ignoring the venafi-cloud.upload_path field in the config file. In %s mode, this field is not needed.`, res.OutputMode))
531654
}
532655
uploadPath = ""
656+
case NGTS:
657+
// NGTS mode doesn't use the upload_path field
658+
if cfg.VenafiCloud != nil && cfg.VenafiCloud.UploadPath != "" {
659+
log.Info(fmt.Sprintf(`ignoring the venafi-cloud.upload_path field in the config file. In %s mode, this field is not needed.`, res.OutputMode))
660+
}
661+
uploadPath = ""
533662
}
534663
res.UploadPath = uploadPath
535664
}
@@ -555,6 +684,13 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
555684
var clusterID string // Required by the old jetstack-secure mode deprecated for venafi cloud modes.
556685
var organizationID string // Only used by the old jetstack-secure mode.
557686
switch res.OutputMode { // nolint:exhaustive
687+
case NGTS:
688+
// NGTS mode requires cluster_name
689+
if cfg.ClusterName == "" {
690+
errs = multierror.Append(errs, fmt.Errorf("cluster_name is required in %s mode", res.OutputMode))
691+
}
692+
clusterName = cfg.ClusterName
693+
// cluster_id and organization_id were already validated to not be present in NGTS mode
558694
case VenafiCloudKeypair, VenafiCloudVenafiConnection:
559695
// For backwards compatibility, use the agent config's `cluster_id` as
560696
// ClusterName if `cluster_name` is not set.
@@ -820,6 +956,27 @@ func validateCredsAndCreateClient(log logr.Logger, flagCredentialsPath, flagClie
820956
if err != nil {
821957
errs = multierror.Append(errs, err)
822958
}
959+
case NGTS:
960+
var creds *client.NGTSServiceAccountCredentials
961+
962+
if flagClientID == "" || flagPrivateKeyPath == "" {
963+
errs = multierror.Append(errs, fmt.Errorf("both --client-id and --private-key-path are required for NGTS mode"))
964+
break
965+
}
966+
967+
creds = &client.NGTSServiceAccountCredentials{
968+
ClientID: flagClientID,
969+
PrivateKeyFile: flagPrivateKeyPath,
970+
}
971+
972+
// rootCAs can be used in future to support custom CA certs, but for now will remain empty
973+
var rootCAs *x509.CertPool
974+
975+
var err error
976+
outputClient, err = client.NewNGTSClient(metadata, creds, cfg.Server, cfg.TSGID, rootCAs)
977+
if err != nil {
978+
errs = multierror.Append(errs, err)
979+
}
823980
default:
824981
panic(fmt.Errorf("programmer mistake: output mode not implemented: %s", cfg.OutputMode))
825982
}

0 commit comments

Comments
 (0)