@@ -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 Security 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
183194func 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 Security 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,55 @@ 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+ if cfg .ClusterID != "" {
557+ errs = multierror .Append (errs , fmt .Errorf ("cluster_id in config file is not supported in NGTS mode. Use cluster_name instead." ))
558+ }
559+
560+ res .TSGID = flags .TSGID
561+ res .NGTSServerURL = flags .NGTSServerURL
562+ }
563+
466564 // Validation and defaulting of `server` and the deprecated `endpoint.path`.
467565 {
468566 // Only relevant if using TLSPK backends
@@ -491,15 +589,31 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
491589 // The VenafiCloudVenafiConnection mode doesn't need a server.
492590 server = client .VenafiCloudProdURL
493591 }
592+ if res .OutputMode == NGTS {
593+ // In NGTS mode, use NGTSServerURL if provided, otherwise we'll use a default
594+ // (which will be determined when creating the client)
595+ server = res .NGTSServerURL
596+ }
597+ }
598+
599+ // For NGTS mode with custom server URL
600+ if res .OutputMode == NGTS && res .NGTSServerURL != "" {
601+ log .Info ("Using custom NGTS server URL (for testing)" , "url" , res .NGTSServerURL )
602+ server = res .NGTSServerURL
494603 }
604+
495605 url , urlErr := url .Parse (server )
496- if urlErr != nil || url .Hostname () == "" {
606+ if urlErr != nil || ( url .Hostname () == "" && server != "" ) {
497607 errs = multierror .Append (errs , fmt .Errorf ("server %q is not a valid URL" , server ))
498608 }
499609 if res .OutputMode == VenafiCloudVenafiConnection && server != "" {
500610 log .Info (fmt .Sprintf ("ignoring the server field specified in the config file. In %s mode, this field is not needed." , VenafiCloudVenafiConnection ))
501611 server = ""
502612 }
613+ if res .OutputMode == NGTS && cfg .Server != "" && res .NGTSServerURL == "" {
614+ log .Info (fmt .Sprintf ("ignoring the server field specified in the config file. In %s mode, use --ngts-server-url for testing." , NGTS ))
615+ server = res .NGTSServerURL
616+ }
503617 res .Server = server
504618 res .EndpointPath = endpointPath
505619 }
@@ -530,6 +644,12 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
530644 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 ))
531645 }
532646 uploadPath = ""
647+ case NGTS :
648+ // NGTS mode doesn't use the upload_path field
649+ if cfg .VenafiCloud != nil && cfg .VenafiCloud .UploadPath != "" {
650+ 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 ))
651+ }
652+ uploadPath = ""
533653 }
534654 res .UploadPath = uploadPath
535655 }
@@ -555,6 +675,13 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
555675 var clusterID string // Required by the old jetstack-secure mode deprecated for venafi cloud modes.
556676 var organizationID string // Only used by the old jetstack-secure mode.
557677 switch res .OutputMode { // nolint:exhaustive
678+ case NGTS :
679+ // NGTS mode requires cluster_name
680+ if cfg .ClusterName == "" {
681+ errs = multierror .Append (errs , fmt .Errorf ("cluster_name is required in %s mode" , res .OutputMode ))
682+ }
683+ clusterName = cfg .ClusterName
684+ // cluster_id and organization_id were already validated to not be present in NGTS mode
558685 case VenafiCloudKeypair , VenafiCloudVenafiConnection :
559686 // For backwards compatibility, use the agent config's `cluster_id` as
560687 // ClusterName if `cluster_name` is not set.
@@ -820,6 +947,27 @@ func validateCredsAndCreateClient(log logr.Logger, flagCredentialsPath, flagClie
820947 if err != nil {
821948 errs = multierror .Append (errs , err )
822949 }
950+ case NGTS :
951+ var creds * client.NGTSServiceAccountCredentials
952+
953+ if flagClientID == "" || flagPrivateKeyPath == "" {
954+ errs = multierror .Append (errs , fmt .Errorf ("both --client-id and --private-key-path are required for NGTS mode" ))
955+ break
956+ }
957+
958+ creds = & client.NGTSServiceAccountCredentials {
959+ ClientID : flagClientID ,
960+ PrivateKeyFile : flagPrivateKeyPath ,
961+ }
962+
963+ // rootCAs can be used in future to support custom CA certs, but for now will remain empty
964+ var rootCAs * x509.CertPool
965+
966+ var err error
967+ outputClient , err = client .NewNGTSClient (metadata , creds , cfg .Server , cfg .TSGID , rootCAs )
968+ if err != nil {
969+ errs = multierror .Append (errs , err )
970+ }
823971 default :
824972 panic (fmt .Errorf ("programmer mistake: output mode not implemented: %s" , cfg .OutputMode ))
825973 }
0 commit comments