Skip to content

Commit a27e40a

Browse files
authored
Merge pull request #812 from jetstack/no_change
Make --tsg-id and --ngts-server-url mutually exclusive
2 parents 9bf7abd + 81729e8 commit a27e40a

11 files changed

Lines changed: 116 additions & 62 deletions

File tree

.github/workflows/tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ jobs:
146146
- run: make -j ngts-test-e2e
147147
env:
148148
OCI_BASE: ${{ secrets.NGTS_OCI_BASE }}
149-
NGTS_CLIENT_ID: ${{ secrets.NGTS_CLIENT_ID }}
149+
NGTS_CLIENT_ID: e3c8bde7-5f13-11f1-99f4-5e067e231041
150150
NGTS_PRIVATE_KEY: ${{ secrets.NGTS_PRIVATE_KEY }}
151-
NGTS_TSG_ID: ${{ secrets.NGTS_TSG_ID }}
151+
NGTS_TSG_URL: https://1806660206.ngts.qa.venafi.io
152152

153153
test-e2e:
154154
if: contains(github.event.pull_request.labels.*.name, 'test-e2e')

deploy/charts/discovery-agent/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The Discovery Agent connects your Kubernetes or OpenShift cluster to Palo Alto N
1212
> ""
1313
> ```
1414
15-
Required: The TSG (Tenant Service Group) ID to use when connecting to SCM.
15+
The TSG (Tenant Service Group) ID to use when connecting to SCM. The production SCM server URL is derived from this value. Required unless config.serverURL is set. Mutually exclusive with config.serverURL.
1616
1717
1818
#### **config.clusterName** ~ `string`

deploy/charts/discovery-agent/templates/deployment.yaml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,14 @@ spec:
7272
- "-c"
7373
- "/etc/discovery-agent/config.yaml"
7474
- --ngts
75-
- --tsg-id
76-
- {{ required "config.tsgID is required" .Values.config.tsgID | include "discovery-agent.stringOrNumber" | quote }}
77-
{{- with .Values.config.serverURL }}
75+
{{- if and .Values.config.tsgID .Values.config.serverURL }}
76+
{{- fail "config.tsgID and config.serverURL are mutually exclusive; set exactly one" }}
77+
{{- else if .Values.config.serverURL }}
7878
- --ngts-server-url
79-
- {{ . | quote }}
79+
- {{ .Values.config.serverURL | quote }}
80+
{{- else }}
81+
- --tsg-id
82+
- {{ required "config.tsgID is required when config.serverURL is not set" .Values.config.tsgID | include "discovery-agent.stringOrNumber" | quote }}
8083
{{- end }}
8184
{{- if or .Values.config.clientID .Values.config.clientId }}
8285
- --client-id

deploy/charts/discovery-agent/tests/deployment_test.yaml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,9 @@ tests:
165165
path: spec.template.spec.containers[0].args
166166
content: --enable-pprof
167167

168-
- it: should include custom server URL when set
168+
- it: should include custom server URL when set, omitting --tsg-id
169169
set:
170170
config.clusterName: test-cluster
171-
config.tsgID: "123456"
172171
config.serverURL: "https://custom.example.com"
173172
asserts:
174173
- contains:
@@ -177,6 +176,25 @@ tests:
177176
- contains:
178177
path: spec.template.spec.containers[0].args
179178
content: "https://custom.example.com"
179+
- notContains:
180+
path: spec.template.spec.containers[0].args
181+
content: --tsg-id
182+
183+
- it: should fail when both tsgID and serverURL are set
184+
set:
185+
config.clusterName: test-cluster
186+
config.tsgID: "123456"
187+
config.serverURL: "https://custom.example.com"
188+
asserts:
189+
- failedTemplate:
190+
errorMessage: "config.tsgID and config.serverURL are mutually exclusive; set exactly one"
191+
192+
- it: should fail when neither tsgID nor serverURL is set
193+
set:
194+
config.clusterName: test-cluster
195+
asserts:
196+
- failedTemplate:
197+
errorMessage: "config.tsgID is required when config.serverURL is not set"
180198

181199
- it: should include client ID when set
182200
set:

deploy/charts/discovery-agent/values.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,12 @@
178178
},
179179
"helm-values.config.serverURL": {
180180
"default": "",
181-
"description": "Explicit SCM server URL (optional).\nIf not set, a production SCM server URL will be created based on the TSG ID. This value is intended for development purposes only and should not be set in production.",
181+
"description": "Explicit SCM server URL (optional).\nIf not set, the production SCM server URL is derived from config.tsgID. This value is intended for development purposes only and should not be set in production.\nMutually exclusive with config.tsgID.",
182182
"type": "string"
183183
},
184184
"helm-values.config.tsgID": {
185185
"default": "",
186-
"description": "Required: The TSG (Tenant Service Group) ID to use when connecting to SCM."
186+
"description": "The TSG (Tenant Service Group) ID to use when connecting to SCM. The production SCM server URL is derived from this value. Required unless config.serverURL is set. Mutually exclusive with config.serverURL."
187187
},
188188
"helm-values.extraArgs": {
189189
"default": [],

deploy/charts/discovery-agent/values.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Configuration for the Discovery Agent
22
config:
3-
# Required: The TSG (Tenant Service Group) ID to use when connecting to SCM.
3+
# The TSG (Tenant Service Group) ID to use when connecting to SCM.
4+
# The production SCM server URL is derived from this value.
5+
# Required unless config.serverURL is set. Mutually exclusive with config.serverURL.
46
# +docs:property
57
# +docs:type=number,string
68
tsgID: ""
@@ -61,8 +63,9 @@ config:
6163
secretName: discovery-agent-credentials
6264

6365
# Explicit SCM server URL (optional).
64-
# If not set, a production SCM server URL will be created based on the TSG ID.
66+
# If not set, the production SCM server URL is derived from config.tsgID.
6567
# This value is intended for development purposes only and should not be set in production.
68+
# Mutually exclusive with config.tsgID.
6669
# +docs:hidden
6770
serverURL: ""
6871

hack/ngts/test-e2e.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ set -o pipefail
2020
# NGTS API configuration
2121
: ${NGTS_CLIENT_ID?}
2222
: ${NGTS_PRIVATE_KEY?}
23-
: ${NGTS_TSG_ID?}
23+
: ${NGTS_TSG_URL?}
2424

2525
# The base URL of the OCI registry used for Docker images and Helm charts
2626
# E.g. ttl.sh/7e6ca67c-96dc-4dea-9437-80b0f3a69fb1
@@ -77,18 +77,17 @@ pprof:
7777
7878
fullnameOverride: discovery-agent
7979
80-
imageRegistry: ${OCI_BASE}
80+
imageRegistry: "${OCI_BASE}"
8181
imageNamespace: ""
8282
8383
image:
84-
digest: ${NGTS_IMAGE_DIGEST}
84+
digest: "${NGTS_IMAGE_DIGEST}"
8585
8686
config:
8787
clusterName: "e2e-test-cluster-ngts"
8888
clusterDescription: "A temporary cluster for E2E testing NGTS"
8989
period: 10s
90-
tsgID: "${NGTS_TSG_ID}"
91-
serverURL: "https://${NGTS_TSG_ID}.ngts.dev.venafi.io"
90+
serverURL: "${NGTS_TSG_URL}"
9291
9392
podLabels:
9493
"discovery-agent.ngts/test-id": "${RANDOM}"

pkg/agent/config.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,13 @@ type AgentCmdFlags struct {
188188
NGTSMode bool
189189

190190
// TSGID (--tsg-id) is the TSG (Tenant Service Group) ID for NGTS mode.
191+
// The production NGTS server URL is derived from this value. Mutually
192+
// exclusive with --ngts-server-url.
191193
TSGID string
192194

193195
// NGTSServerURL (--ngts-server-url) is a hidden flag for developers to
194-
// override the NGTS server URL for testing purposes.
196+
// point the agent at a custom NGTS server URL for testing purposes.
197+
// Mutually exclusive with --tsg-id.
195198
NGTSServerURL string
196199
}
197200

@@ -350,13 +353,15 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) {
350353
"ngts",
351354
false,
352355
"Enables NGTS mode. The agent will authenticate using key pair authentication and send data to NGTS endpoints. "+
353-
"Must be used in conjunction with --tsg-id and --private-key-path. --client-id is optional if provided in the credentials secret.",
356+
"Must be used with --private-key-path and exactly one of --tsg-id or --ngts-server-url. "+
357+
"--client-id is optional if provided in the credentials secret.",
354358
)
355359
c.PersistentFlags().StringVar(
356360
&cfg.TSGID,
357361
"tsg-id",
358362
"",
359-
"The TSG (Tenant Service Group) ID for NGTS mode. Required when using --ngts.",
363+
"The TSG (Tenant Service Group) ID for NGTS mode. The production NGTS server URL is derived from this value. "+
364+
"Mutually exclusive with --ngts-server-url; exactly one must be provided when using --ngts.",
360365
)
361366

362367
ngtsServerURLFlag := "ngts-server-url"
@@ -365,7 +370,8 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) {
365370
&cfg.NGTSServerURL,
366371
ngtsServerURLFlag,
367372
"",
368-
"Override the NGTS server URL for testing purposes. This flag is intended for agent development and should not need to be set.",
373+
"Override the NGTS server URL for testing purposes. This flag is intended for agent development and should not need to be set. "+
374+
"Mutually exclusive with --tsg-id.",
369375
)
370376

371377
// ngts-server-url is intended only for developers, so hide it from help
@@ -505,7 +511,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
505511
default:
506512
return CombinedConfig{}, nil, fmt.Errorf("no output mode specified. " +
507513
"To enable one of the output modes, you can:\n" +
508-
" - Use --ngts with --tsg-id and --private-key-path to use the " + string(NGTS) + " mode (--client-id is optional if provided in the credentials secret).\n" +
514+
" - Use --ngts with --private-key-path and exactly one of --tsg-id or --ngts-server-url to use the " + string(NGTS) + " mode (--client-id is optional if provided in the credentials secret).\n" +
509515
" - Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the " + string(VenafiCloudKeypair) + " mode.\n" +
510516
" - Use --venafi-connection for the " + string(VenafiCloudVenafiConnection) + " mode.\n" +
511517
" - Use --credentials-file alone if you want to use the " + string(JetstackSecureOAuth) + " mode.\n" +
@@ -523,8 +529,11 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
523529

524530
// Validation of NGTS mode requirements.
525531
if res.OutputMode == NGTS {
526-
if flags.TSGID == "" {
527-
errs = multierror.Append(errs, fmt.Errorf("--tsg-id is required when using --ngts"))
532+
switch {
533+
case flags.TSGID != "" && flags.NGTSServerURL != "":
534+
errs = multierror.Append(errs, fmt.Errorf("--tsg-id and --ngts-server-url are mutually exclusive; exactly one must be provided when using --ngts"))
535+
case flags.TSGID == "" && flags.NGTSServerURL == "":
536+
errs = multierror.Append(errs, fmt.Errorf("either --tsg-id or --ngts-server-url is required when using --ngts"))
528537
}
529538
if flags.PrivateKeyPath == "" {
530539
errs = multierror.Append(errs, fmt.Errorf("--private-key-path is required when using --ngts"))

pkg/agent/config_test.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func Test_ValidateAndCombineConfig(t *testing.T) {
195195
)
196196
assert.EqualError(t, err, testutil.Undent(`
197197
no output mode specified. To enable one of the output modes, you can:
198-
- Use --ngts with --tsg-id and --private-key-path to use the NGTS mode (--client-id is optional if provided in the credentials secret).
198+
- Use --ngts with --private-key-path and exactly one of --tsg-id or --ngts-server-url to use the NGTS mode (--client-id is optional if provided in the credentials secret).
199199
- Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the Venafi Cloud Key Pair Service Account mode.
200200
- Use --venafi-connection for the Venafi Cloud VenafiConnection mode.
201201
- Use --credentials-file alone if you want to use the Jetstack Secure OAuth mode.
@@ -1124,28 +1124,28 @@ func Test_ValidateAndCombineConfig_NGTS(t *testing.T) {
11241124
period: 1h
11251125
cluster_name: test-cluster
11261126
`)),
1127-
withCmdLineFlags("--ngts", "--tsg-id", "test-tsg-123", "--client-id", "test-client-id", "--private-key-path", privKeyPath, "--ngts-server-url", "https://ngts.test.example.com"))
1127+
withCmdLineFlags("--ngts", "--client-id", "test-client-id", "--private-key-path", privKeyPath, "--ngts-server-url", "https://ngts.test.example.com"))
11281128
require.NoError(t, err)
11291129
assert.Equal(t, NGTS, got.OutputMode)
1130+
assert.Equal(t, "", got.TSGID)
11301131
assert.Equal(t, "https://ngts.test.example.com", got.NGTSServerURL)
11311132
assert.IsType(t, &client.NGTSClient{}, cl)
11321133
})
11331134

1134-
t.Run("ngts: missing --ngts flag should not trigger NGTS mode", func(t *testing.T) {
1135+
t.Run("ngts: --tsg-id and --ngts-server-url are mutually exclusive", func(t *testing.T) {
11351136
t.Setenv("POD_NAMESPACE", "venafi")
11361137
privKeyPath := withFile(t, fakePrivKeyPEM)
11371138
_, _, err := ValidateAndCombineConfig(discardLogs(),
11381139
withConfig(testutil.Undent(`
11391140
period: 1h
11401141
cluster_name: test-cluster
11411142
`)),
1142-
withCmdLineFlags("--tsg-id", "test-tsg-123", "--client-id", "test-client-id", "--private-key-path", privKeyPath))
1143-
// Should select VenafiCloudKeypair mode instead when --ngts is not specified
1143+
withCmdLineFlags("--ngts", "--tsg-id", "test-tsg-123", "--client-id", "test-client-id", "--private-key-path", privKeyPath, "--ngts-server-url", "https://ngts.test.example.com"))
11441144
require.Error(t, err)
1145-
assert.Contains(t, err.Error(), "venafi-cloud.upload_path")
1145+
assert.Contains(t, err.Error(), "--tsg-id and --ngts-server-url are mutually exclusive")
11461146
})
11471147

1148-
t.Run("ngts: missing --tsg-id should error", func(t *testing.T) {
1148+
t.Run("ngts: missing both --tsg-id and --ngts-server-url should error", func(t *testing.T) {
11491149
t.Setenv("POD_NAMESPACE", "venafi")
11501150
privKeyPath := withFile(t, fakePrivKeyPEM)
11511151
_, _, err := ValidateAndCombineConfig(discardLogs(),
@@ -1155,7 +1155,21 @@ func Test_ValidateAndCombineConfig_NGTS(t *testing.T) {
11551155
`)),
11561156
withCmdLineFlags("--ngts", "--client-id", "test-client-id", "--private-key-path", privKeyPath))
11571157
require.Error(t, err)
1158-
assert.Contains(t, err.Error(), "--tsg-id is required when using --ngts")
1158+
assert.Contains(t, err.Error(), "either --tsg-id or --ngts-server-url is required when using --ngts")
1159+
})
1160+
1161+
t.Run("ngts: missing --ngts flag should not trigger NGTS mode", func(t *testing.T) {
1162+
t.Setenv("POD_NAMESPACE", "venafi")
1163+
privKeyPath := withFile(t, fakePrivKeyPEM)
1164+
_, _, err := ValidateAndCombineConfig(discardLogs(),
1165+
withConfig(testutil.Undent(`
1166+
period: 1h
1167+
cluster_name: test-cluster
1168+
`)),
1169+
withCmdLineFlags("--tsg-id", "test-tsg-123", "--client-id", "test-client-id", "--private-key-path", privKeyPath))
1170+
// Should select VenafiCloudKeypair mode instead when --ngts is not specified
1171+
require.Error(t, err)
1172+
assert.Contains(t, err.Error(), "venafi-cloud.upload_path")
11591173
})
11601174

11611175
t.Run("ngts: missing --client-id should error", func(t *testing.T) {

pkg/client/client_ngts.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ type NGTSClient struct {
3838
baseURL *url.URL
3939
agentMetadata *api.AgentMetadata
4040

41-
tsgID string
4241
privateKey crypto.PrivateKey
4342
jwtSigningAlg jwt.SigningMethod
4443
lock sync.RWMutex
@@ -87,8 +86,8 @@ const (
8786
)
8887

8988
// NewNGTSClient creates a new NGTS client that authenticates using keypair authentication
90-
// and uploads data to NGTS endpoints. The baseURL parameter can override the default
91-
// NGTS server URL for testing purposes.
89+
// and uploads data to NGTS endpoints. Exactly one of tsgID or baseURL must be provided:
90+
// tsgID derives the production NGTS URL; baseURL sets a custom URL for testing.
9291
func NewNGTSClient(agentMetadata *api.AgentMetadata, credentials *NGTSServiceAccountCredentials, baseURL string, tsgID string, rootCAs *x509.CertPool) (*NGTSClient, error) {
9392
// Load ClientID from file if not provided directly
9493
if err := credentials.LoadClientIDIfNeeded(); err != nil {
@@ -103,8 +102,11 @@ func NewNGTSClient(agentMetadata *api.AgentMetadata, credentials *NGTSServiceAcc
103102
// https://pan.dev/scm/api/tenancy/delete-tenancy-v-1-tenant-service-groups-tsg-id/
104103
// > Possible values: >= 10 characters and <= 10 characters, Value must match regular expression ^1[0-9]+$
105104
// For now, leaving this check simple
106-
if tsgID == "" {
107-
return nil, fmt.Errorf("cannot create NGTSClient: tsgID cannot be empty")
105+
switch {
106+
case tsgID != "" && baseURL != "":
107+
return nil, fmt.Errorf("cannot create NGTSClient: tsgID and baseURL are mutually exclusive; exactly one must be provided")
108+
case tsgID == "" && baseURL == "":
109+
return nil, fmt.Errorf("cannot create NGTSClient: either tsgID or baseURL must be provided")
108110
}
109111

110112
privateKey, jwtSigningAlg, err := parsePrivateKeyAndExtractSigningMethod(credentials.PrivateKeyFile)
@@ -113,8 +115,6 @@ func NewNGTSClient(agentMetadata *api.AgentMetadata, credentials *NGTSServiceAcc
113115
}
114116

115117
actualBaseURL := baseURL
116-
117-
// Create prod NGTS URL if no explicit URL provided
118118
if actualBaseURL == "" {
119119
actualBaseURL = fmt.Sprintf(ngtsProdURLFormat, tsgID)
120120
}
@@ -145,7 +145,6 @@ func NewNGTSClient(agentMetadata *api.AgentMetadata, credentials *NGTSServiceAcc
145145
agentMetadata: agentMetadata,
146146
credentials: credentials,
147147
baseURL: parsedBaseURL,
148-
tsgID: tsgID,
149148
accessToken: &ngtsAccessToken{},
150149
Client: &http.Client{
151150
Timeout: time.Minute,

0 commit comments

Comments
 (0)