@@ -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
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 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