diff --git a/deploy/charts/discovery-agent/README.md b/deploy/charts/discovery-agent/README.md index f182efdf..80ca29e1 100644 --- a/deploy/charts/discovery-agent/README.md +++ b/deploy/charts/discovery-agent/README.md @@ -12,7 +12,7 @@ The Discovery Agent connects your Kubernetes or OpenShift cluster to Palo Alto N > "" > ``` -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. +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. Must not be set when config.venafiConnection.enabled is true (the TSG ID is taken from the VenafiConnection's `spec.ngts` instead). #### **config.clusterName** ~ `string` @@ -72,7 +72,7 @@ Example: excludeAnnotationKeysRegex: ['^kapp\.k14s\.io/original.*'] > "" > ``` -Deprecated: Client ID for the configured service account. The client ID should be provided in the "clientID" field of the authentication secret (see config.secretName). This field is provided for compatibility for users migrating from the "venafi-kubernetes-agent" chart. +Deprecated: Client ID for the configured service account. The client ID should be provided in the "clientID" field of the authentication secret (see config.secretName). This field is provided for compatibility for users migrating from the "venafi-kubernetes-agent" chart. Must not be set when config.venafiConnection.enabled is true. #### **config.secretName** ~ `string` > Default value: @@ -84,8 +84,30 @@ The name of the Secret containing the NGTS built-in service account credentials. The Secret must contain the following key: - privatekey.pem: PEM-encoded private key for the service account The Secret should also contain the following key: -- clientID: Service account client ID (config.clientID must be set if not present) +- clientID: Service account client ID (config.clientID must be set if not present) +Must not be set when config.venafiConnection.enabled is true (the credentials Secret is not mounted in that mode). +#### **config.venafiConnection.enabled** ~ `bool` +> Default value: +> ```yaml +> false +> ``` + +When set to true, config.tsgID, config.serverURL, config.clientID and config.clientId must not be set (the chart will fail to render otherwise), and the Secret named by config.secretName will _not_ be mounted into the Discovery Agent Pod. +#### **config.venafiConnection.name** ~ `string` +> Default value: +> ```yaml +> venafi-components +> ``` + +The name of a VenafiConnection resource which contains the configuration for authenticating to the upload backend. +#### **config.venafiConnection.namespace** ~ `string` +> Default value: +> ```yaml +> venafi +> ``` + +The namespace of a VenafiConnection resource which contains the configuration for authenticating to the upload backend. #### **replicaCount** ~ `number` > Default value: > ```yaml diff --git a/deploy/charts/discovery-agent/templates/deployment.yaml b/deploy/charts/discovery-agent/templates/deployment.yaml index fdde00f4..04abcada 100644 --- a/deploy/charts/discovery-agent/templates/deployment.yaml +++ b/deploy/charts/discovery-agent/templates/deployment.yaml @@ -71,6 +71,27 @@ spec: - "agent" - "-c" - "/etc/discovery-agent/config.yaml" + {{- if .Values.config.venafiConnection.enabled }} + {{- if .Values.config.tsgID }} + {{- fail "config.tsgID must not be set when config.venafiConnection.enabled is true; the TSG ID is read from the VenafiConnection's spec.ngts" }} + {{- end }} + {{- if .Values.config.serverURL }} + {{- fail "config.serverURL must not be set when config.venafiConnection.enabled is true; the server URL is read from the VenafiConnection's spec" }} + {{- end }} + {{- if .Values.config.clientID }} + {{- fail "config.clientID must not be set when config.venafiConnection.enabled is true; authentication is performed via the VenafiConnection resource" }} + {{- end }} + {{- if .Values.config.clientId }} + {{- fail "config.clientId must not be set when config.venafiConnection.enabled is true; authentication is performed via the VenafiConnection resource" }} + {{- end }} + {{- if ne .Values.config.secretName "discovery-agent-credentials" }} + {{- fail "config.secretName must not be set when config.venafiConnection.enabled is true; the credentials Secret is not mounted in this mode (authentication is performed via the VenafiConnection resource)" }} + {{- end }} + - --venafi-connection + - {{ .Values.config.venafiConnection.name | quote }} + - --venafi-connection-namespace + - {{ .Values.config.venafiConnection.namespace | quote }} + {{- else }} - --ngts {{- if and .Values.config.tsgID .Values.config.serverURL }} {{- fail "config.tsgID and config.serverURL are mutually exclusive; set exactly one" }} @@ -87,6 +108,7 @@ spec: {{- end }} - --private-key-path - /etc/discovery-agent/credentials/privatekey.pem + {{- end }} - --logging-format=json {{- if .Values.metrics.enabled }} - --enable-metrics @@ -105,9 +127,11 @@ spec: - name: config mountPath: "/etc/discovery-agent" readOnly: true + {{- if not .Values.config.venafiConnection.enabled }} - name: credentials mountPath: "/etc/discovery-agent/credentials" readOnly: true + {{- end }} {{- with .Values.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} @@ -119,10 +143,12 @@ spec: configMap: name: {{ include "discovery-agent.fullname" . }}-config optional: false + {{- if not .Values.config.venafiConnection.enabled }} - name: credentials secret: secretName: {{ .Values.config.secretName }} optional: false + {{- end }} {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/deploy/charts/discovery-agent/tests/deployment_test.yaml b/deploy/charts/discovery-agent/tests/deployment_test.yaml index 35f47ec5..06def8c2 100644 --- a/deploy/charts/discovery-agent/tests/deployment_test.yaml +++ b/deploy/charts/discovery-agent/tests/deployment_test.yaml @@ -373,3 +373,131 @@ tests: path: spec.template.spec.imagePullSecrets content: name: my-secret + + # VenafiConnection mode wires the connection name/namespace through as flags + # and skips both the --ngts/--tsg-id flags and the keypair Secret mount. The + # agent picks the actual upload backend (NGTS or VCP) from the + # VenafiConnection resource at runtime. + - it: VenafiConnection mode passes the connection flags and omits NGTS/keypair flags + set: + config.clusterName: test-cluster + config.venafiConnection.enabled: true + config.venafiConnection.name: my-venconn + config.venafiConnection.namespace: my-ns + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - contains: + path: spec.template.spec.containers[0].args + content: --venafi-connection + - contains: + path: spec.template.spec.containers[0].args + content: my-venconn + - contains: + path: spec.template.spec.containers[0].args + content: --venafi-connection-namespace + - contains: + path: spec.template.spec.containers[0].args + content: my-ns + - notContains: + path: spec.template.spec.containers[0].args + content: --ngts + - notContains: + path: spec.template.spec.containers[0].args + content: --tsg-id + - notContains: + path: spec.template.spec.containers[0].args + content: --ngts-server-url + - notContains: + path: spec.template.spec.containers[0].args + content: --client-id + - notContains: + path: spec.template.spec.containers[0].args + content: --private-key-path + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: credentials + mountPath: "/etc/discovery-agent/credentials" + readOnly: true + - notContains: + path: spec.template.spec.volumes + content: + name: credentials + secret: + secretName: discovery-agent-credentials + optional: false + + # VenafiConnection mode does not require config.tsgID, since the agent reads + # the TSG ID from the VenafiConnection resource at runtime. + - it: VenafiConnection mode does not require config.tsgID + set: + config.clusterName: test-cluster + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - isKind: + of: Deployment + + # Keypair-mode fields must not be set in VenafiConnection mode; the chart + # should fail to render rather than silently dropping the values, so users + # don't end up with a config that looks wired but isn't. + - it: VenafiConnection mode rejects config.tsgID + set: + config.clusterName: test-cluster + config.tsgID: "999" + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - failedTemplate: + errorMessage: "config.tsgID must not be set when config.venafiConnection.enabled is true; the TSG ID is read from the VenafiConnection's spec.ngts" + + - it: VenafiConnection mode rejects config.serverURL + set: + config.clusterName: test-cluster + config.serverURL: "https://should-be-rejected.example.com" + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - failedTemplate: + errorMessage: "config.serverURL must not be set when config.venafiConnection.enabled is true; the server URL is read from the VenafiConnection's spec" + + - it: VenafiConnection mode rejects config.clientID + set: + config.clusterName: test-cluster + config.clientID: "should-be-rejected" + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - failedTemplate: + errorMessage: "config.clientID must not be set when config.venafiConnection.enabled is true; authentication is performed via the VenafiConnection resource" + + - it: VenafiConnection mode rejects config.clientId + set: + config.clusterName: test-cluster + config.clientId: "should-be-rejected" + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - failedTemplate: + errorMessage: "config.clientId must not be set when config.venafiConnection.enabled is true; authentication is performed via the VenafiConnection resource" + + - it: VenafiConnection mode rejects a non-default config.secretName + set: + config.clusterName: test-cluster + config.secretName: custom-credentials-secret + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - failedTemplate: + errorMessage: "config.secretName must not be set when config.venafiConnection.enabled is true; the credentials Secret is not mounted in this mode (authentication is performed via the VenafiConnection resource)" + + - it: VenafiConnection mode accepts the default config.secretName + set: + config.clusterName: test-cluster + config.venafiConnection.enabled: true + template: deployment.yaml + asserts: + - isKind: + of: Deployment diff --git a/deploy/charts/discovery-agent/values.schema.json b/deploy/charts/discovery-agent/values.schema.json index f40d6e24..2cfaca99 100644 --- a/deploy/charts/discovery-agent/values.schema.json +++ b/deploy/charts/discovery-agent/values.schema.json @@ -126,6 +126,9 @@ }, "tsgID": { "$ref": "#/$defs/helm-values.config.tsgID" + }, + "venafiConnection": { + "$ref": "#/$defs/helm-values.config.venafiConnection" } }, "type": "object" @@ -137,12 +140,12 @@ }, "helm-values.config.clientID": { "default": "", - "description": "Deprecated: Client ID for the configured service account. The client ID should be provided in the \"clientID\" field of the authentication secret (see config.secretName). This field is provided for compatibility for users migrating from the \"venafi-kubernetes-agent\" chart.", + "description": "Deprecated: Client ID for the configured service account. The client ID should be provided in the \"clientID\" field of the authentication secret (see config.secretName). This field is provided for compatibility for users migrating from the \"venafi-kubernetes-agent\" chart. Must not be set when config.venafiConnection.enabled is true.", "type": "string" }, "helm-values.config.clientId": { "default": "", - "description": "Deprecated: Client ID for the configured service account (alternative to clientID). The client ID should be provided in the \"clientID\" field of the authentication secret (see config.secretName). This field is provided for compatibility for users migrating from the \"venafi-kubernetes-agent\" chart. If both clientID and clientId are set, clientID takes precedence.", + "description": "Deprecated: Client ID for the configured service account (alternative to clientID). The client ID should be provided in the \"clientID\" field of the authentication secret (see config.secretName). This field is provided for compatibility for users migrating from the \"venafi-kubernetes-agent\" chart. If both clientID and clientId are set, clientID takes precedence. Must not be set when config.venafiConnection.enabled is true.", "type": "string" }, "helm-values.config.clusterDescription": { @@ -173,17 +176,47 @@ }, "helm-values.config.secretName": { "default": "discovery-agent-credentials", - "description": "The name of the Secret containing the NGTS built-in service account credentials.\nThe Secret must contain the following key:\n- privatekey.pem: PEM-encoded private key for the service account\nThe Secret should also contain the following key:\n- clientID: Service account client ID (config.clientID must be set if not present)", + "description": "The name of the Secret containing the NGTS built-in service account credentials.\nThe Secret must contain the following key:\n- privatekey.pem: PEM-encoded private key for the service account\nThe Secret should also contain the following key:\n- clientID: Service account client ID (config.clientID must be set if not present)\nMust not be set when config.venafiConnection.enabled is true (the credentials Secret is not mounted in that mode).", "type": "string" }, "helm-values.config.serverURL": { "default": "", - "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.", + "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.\nMust not be set when config.venafiConnection.enabled is true.", "type": "string" }, "helm-values.config.tsgID": { "default": "", - "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." + "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. Must not be set when config.venafiConnection.enabled is true (the TSG ID is taken from the VenafiConnection's `spec.ngts` instead)." + }, + "helm-values.config.venafiConnection": { + "additionalProperties": false, + "properties": { + "enabled": { + "$ref": "#/$defs/helm-values.config.venafiConnection.enabled" + }, + "name": { + "$ref": "#/$defs/helm-values.config.venafiConnection.name" + }, + "namespace": { + "$ref": "#/$defs/helm-values.config.venafiConnection.namespace" + } + }, + "type": "object" + }, + "helm-values.config.venafiConnection.enabled": { + "default": false, + "description": "When set to true, config.tsgID, config.serverURL, config.clientID and config.clientId must not be set (the chart will fail to render otherwise), and the Secret named by config.secretName will _not_ be mounted into the Discovery Agent Pod.", + "type": "boolean" + }, + "helm-values.config.venafiConnection.name": { + "default": "venafi-components", + "description": "The name of a VenafiConnection resource which contains the configuration for authenticating to the upload backend.", + "type": "string" + }, + "helm-values.config.venafiConnection.namespace": { + "default": "venafi", + "description": "The namespace of a VenafiConnection resource which contains the configuration for authenticating to the upload backend.", + "type": "string" }, "helm-values.extraArgs": { "default": [], diff --git a/deploy/charts/discovery-agent/values.yaml b/deploy/charts/discovery-agent/values.yaml index b013c959..b76acade 100644 --- a/deploy/charts/discovery-agent/values.yaml +++ b/deploy/charts/discovery-agent/values.yaml @@ -3,6 +3,7 @@ config: # 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. + # Must not be set when config.venafiConnection.enabled is true (the TSG ID is taken from the VenafiConnection's `spec.ngts` instead). # +docs:property # +docs:type=number,string tsgID: "" @@ -44,6 +45,7 @@ config: # Deprecated: Client ID for the configured service account. # The client ID should be provided in the "clientID" field of the authentication secret (see config.secretName). # This field is provided for compatibility for users migrating from the "venafi-kubernetes-agent" chart. + # Must not be set when config.venafiConnection.enabled is true. # +docs:property clientID: "" @@ -51,6 +53,7 @@ config: # The client ID should be provided in the "clientID" field of the authentication secret (see config.secretName). # This field is provided for compatibility for users migrating from the "venafi-kubernetes-agent" chart. # If both clientID and clientId are set, clientID takes precedence. + # Must not be set when config.venafiConnection.enabled is true. # +docs:hidden clientId: "" @@ -59,6 +62,7 @@ config: # - privatekey.pem: PEM-encoded private key for the service account # The Secret should also contain the following key: # - clientID: Service account client ID (config.clientID must be set if not present) + # Must not be set when config.venafiConnection.enabled is true (the credentials Secret is not mounted in that mode). # +docs:property secretName: discovery-agent-credentials @@ -66,9 +70,28 @@ config: # If 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. # Mutually exclusive with config.tsgID. + # Must not be set when config.venafiConnection.enabled is true. # +docs:hidden serverURL: "" + # When venafiConnection.enabled is true, the Discovery Agent authenticates to + # its upload backend using the referenced VenafiConnection resource instead + # of the NGTS built-in service account key pair. For the NGTS backend, the + # VenafiConnection's `spec.ngts` (with `tsgID` or `url`, and a `jwt` source) + # is used. + venafiConnection: + # When set to true, config.tsgID, config.serverURL, config.clientID and + # config.clientId must not be set (the chart will fail to render + # otherwise), and the Secret named by config.secretName will _not_ be + # mounted into the Discovery Agent Pod. + enabled: false + # The name of a VenafiConnection resource which contains the configuration + # for authenticating to the upload backend. + name: venafi-components + # The namespace of a VenafiConnection resource which contains the + # configuration for authenticating to the upload backend. + namespace: venafi + # This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ replicaCount: 1 diff --git a/deploy/charts/venafi-kubernetes-agent/README.md b/deploy/charts/venafi-kubernetes-agent/README.md index 232b8d77..e88e396a 100644 --- a/deploy/charts/venafi-kubernetes-agent/README.md +++ b/deploy/charts/venafi-kubernetes-agent/README.md @@ -390,7 +390,10 @@ Configure VenafiConnection authentication > false > ``` -When set to true, the Discovery Agent will authenticate to CyberArk Certificate Manager using the configuration in a VenafiConnection resource. Use `venafiConnection.enabled=true` for [secretless authentication](https://docs.cyberark.com/mis-saas/vaas/k8s-components/t-install-tlspk-agent/). When set to true, the `authentication.secret` values will be ignored and the. Secret with `authentication.secretName` will _not_ be mounted into the +When set to true, the Discovery Agent will authenticate to its upload backend using the configuration in a VenafiConnection resource. The backend is determined by the VenafiConnection's spec: use `spec.vcp` for CyberArk Certificate Manager (CMSaaS), or `spec.ngts` (with `tsgID` or +`url`, and a `jwt` source) for NGTS / Palo Alto Networks. `spec.tpp` and +`spec.vcp.apiKey` are rejected by the agent. +Use `venafiConnection.enabled=true` for [secretless authentication](https://docs.cyberark.com/mis-saas/vaas/k8s-components/t-install-tlspk-agent/). When set to true, the `authentication.secret` values will be ignored and the Secret with `authentication.secretName` will _not_ be mounted into the Discovery Agent Pod. #### **authentication.venafiConnection.name** ~ `string` > Default value: diff --git a/deploy/charts/venafi-kubernetes-agent/crd_bases/jetstack.io_venaficonnections.yaml b/deploy/charts/venafi-kubernetes-agent/crd_bases/jetstack.io_venaficonnections.yaml index 90cdcb70..9389601d 100644 --- a/deploy/charts/venafi-kubernetes-agent/crd_bases/jetstack.io_venaficonnections.yaml +++ b/deploy/charts/venafi-kubernetes-agent/crd_bases/jetstack.io_venaficonnections.yaml @@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.20.1 + controller-gen.kubebuilder.io/version: v0.21.0 name: venaficonnections.jetstack.io spec: group: jetstack.io diff --git a/deploy/charts/venafi-kubernetes-agent/templates/deployment.yaml b/deploy/charts/venafi-kubernetes-agent/templates/deployment.yaml index 24eb99a9..c582d504 100644 --- a/deploy/charts/venafi-kubernetes-agent/templates/deployment.yaml +++ b/deploy/charts/venafi-kubernetes-agent/templates/deployment.yaml @@ -81,8 +81,8 @@ spec: - {{ .Values.config.clientId | quote }} - "--private-key-path" - "/etc/venafi/agent/key/{{ .Values.authentication.secretKey }}" - {{- end }} - --venafi-cloud + {{- end }} {{- if .Values.metrics.enabled }} - --enable-metrics {{- end }} diff --git a/deploy/charts/venafi-kubernetes-agent/tests/deployment_test.yaml b/deploy/charts/venafi-kubernetes-agent/tests/deployment_test.yaml index f1e27510..9f770ff1 100644 --- a/deploy/charts/venafi-kubernetes-agent/tests/deployment_test.yaml +++ b/deploy/charts/venafi-kubernetes-agent/tests/deployment_test.yaml @@ -133,3 +133,71 @@ tests: - lengthEqual : path: spec.template.spec.containers[0].env count: 4 + + # VenafiConnection mode (used for both VCP and NGTS backends) wires the + # connection name/namespace through as flags and skips mounting the keypair + # Secret. The Secret-based --client-id / --private-key-path flags must not be + # present in this mode. + - it: VenafiConnection mode passes the connection flags and omits the credentials Secret + set: + authentication.venafiConnection.enabled: true + authentication.venafiConnection.name: my-venconn + authentication.venafiConnection.namespace: my-ns + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - contains: + path: spec.template.spec.containers[0].args + content: --venafi-connection + - contains: + path: spec.template.spec.containers[0].args + content: my-venconn + - contains: + path: spec.template.spec.containers[0].args + content: --venafi-connection-namespace + - contains: + path: spec.template.spec.containers[0].args + content: my-ns + - notContains: + path: spec.template.spec.containers[0].args + content: --client-id + - notContains: + path: spec.template.spec.containers[0].args + content: --private-key-path + - notContains: + path: spec.template.spec.containers[0].args + content: --venafi-cloud + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: credentials + mountPath: /etc/venafi/agent/key + readOnly: true + - notContains: + path: spec.template.spec.volumes + content: + name: credentials + secret: + secretName: agent-credentials + optional: false + + # Keypair mode (the default, used when authentication.venafiConnection.enabled + # is false) still renders --venafi-cloud since the agent's mode-resolution + # treats keypair as a Venafi Cloud backend. + - it: Keypair mode still passes --venafi-cloud + set: + config.clientId: "00000000-0000-0000-0000-000000000000" + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - contains: + path: spec.template.spec.containers[0].args + content: --venafi-cloud + - contains: + path: spec.template.spec.containers[0].args + content: --client-id + - contains: + path: spec.template.spec.containers[0].args + content: --private-key-path diff --git a/deploy/charts/venafi-kubernetes-agent/values.schema.json b/deploy/charts/venafi-kubernetes-agent/values.schema.json index 48a04b63..9b31de55 100644 --- a/deploy/charts/venafi-kubernetes-agent/values.schema.json +++ b/deploy/charts/venafi-kubernetes-agent/values.schema.json @@ -137,7 +137,7 @@ }, "helm-values.authentication.venafiConnection.enabled": { "default": false, - "description": "When set to true, the Discovery Agent will authenticate to CyberArk Certificate Manager using the configuration in a VenafiConnection resource. Use `venafiConnection.enabled=true` for [secretless authentication](https://docs.cyberark.com/mis-saas/vaas/k8s-components/t-install-tlspk-agent/). When set to true, the `authentication.secret` values will be ignored and the. Secret with `authentication.secretName` will _not_ be mounted into the\nDiscovery Agent Pod.", + "description": "When set to true, the Discovery Agent will authenticate to its upload backend using the configuration in a VenafiConnection resource. The backend is determined by the VenafiConnection's spec: use `spec.vcp` for CyberArk Certificate Manager (CMSaaS), or `spec.ngts` (with `tsgID` or\n`url`, and a `jwt` source) for NGTS / Palo Alto Networks. `spec.tpp` and\n`spec.vcp.apiKey` are rejected by the agent.\nUse `venafiConnection.enabled=true` for [secretless authentication](https://docs.cyberark.com/mis-saas/vaas/k8s-components/t-install-tlspk-agent/). When set to true, the `authentication.secret` values will be ignored and the Secret with `authentication.secretName` will _not_ be mounted into the\nDiscovery Agent Pod.", "type": "boolean" }, "helm-values.authentication.venafiConnection.name": { diff --git a/deploy/charts/venafi-kubernetes-agent/values.yaml b/deploy/charts/venafi-kubernetes-agent/values.yaml index 92829937..09bc018e 100644 --- a/deploy/charts/venafi-kubernetes-agent/values.yaml +++ b/deploy/charts/venafi-kubernetes-agent/values.yaml @@ -238,11 +238,15 @@ authentication: # +docs:section=Venafi Connection # Configure VenafiConnection authentication venafiConnection: - # When set to true, the Discovery Agent will authenticate to CyberArk Certificate Manager - # using the configuration in a VenafiConnection resource. + # When set to true, the Discovery Agent will authenticate to its upload + # backend using the configuration in a VenafiConnection resource. The + # backend is determined by the VenafiConnection's spec: use `spec.vcp` + # for CyberArk Certificate Manager (CMSaaS), or `spec.ngts` (with `tsgID` or + # `url`, and a `jwt` source) for NGTS / Palo Alto Networks. `spec.tpp` and + # `spec.vcp.apiKey` are rejected by the agent. # Use `venafiConnection.enabled=true` for [secretless authentication](https://docs.cyberark.com/mis-saas/vaas/k8s-components/t-install-tlspk-agent/). - # When set to true, the `authentication.secret` values will be ignored and the - # Secret with `authentication.secretName` will _not_ be mounted into the + # When set to true, the `authentication.secret` values will be ignored and + # the Secret with `authentication.secretName` will _not_ be mounted into the # Discovery Agent Pod. enabled: false # The name of a VenafiConnection resource which contains the configuration diff --git a/go.mod b/go.mod index ca88f6a0..ccbbd358 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/fatih/color v1.19.0 github.com/google/uuid v1.6.0 github.com/hashicorp/go-multierror v1.1.1 - github.com/jetstack/venafi-connection-lib v0.6.0 + github.com/jetstack/venafi-connection-lib v0.6.1-0.20260528121802-f90d3d05ddd5 github.com/lestrrat-go/jwx/v3 v3.1.1 github.com/microcosm-cc/bluemonday v1.0.27 github.com/pmylund/go-cache v2.1.0+incompatible @@ -63,7 +63,7 @@ require ( go.opentelemetry.io/otel v1.41.0 // indirect go.opentelemetry.io/otel/trace v1.41.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect + go.uber.org/zap v1.28.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.50.0 // indirect @@ -74,8 +74,8 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/ini.v1 v1.67.1 // indirect - k8s.io/apiextensions-apiserver v0.36.0 // indirect - k8s.io/apiserver v0.36.0 // indirect + k8s.io/apiextensions-apiserver v0.36.1 // indirect + k8s.io/apiserver v0.36.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect ) @@ -112,6 +112,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 k8s.io/klog/v2 v2.140.0 k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect - k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect + k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect ) diff --git a/go.sum b/go.sum index 92d9f01c..a13e4c26 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jetstack/venafi-connection-lib v0.6.0 h1:ZVR06xfJdWTKfIjVK3v4oPgc68TZNd9cYZmsi+9prFg= -github.com/jetstack/venafi-connection-lib v0.6.0/go.mod h1:XEjTVju/2ROnUEDQAyAm0Rj7Mk7HJF0/bwmS67KbwQA= +github.com/jetstack/venafi-connection-lib v0.6.1-0.20260528121802-f90d3d05ddd5 h1:bF8CfskHNjfxm5dcIhMKBSa+hWvSR0rQEzFxXcj3dBw= +github.com/jetstack/venafi-connection-lib v0.6.1-0.20260528121802-f90d3d05ddd5/go.mod h1:KPndhwwPHPkBqv7cocVTtEDPHV/CBrwapLqzUnwbCUs= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -238,8 +238,8 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -293,12 +293,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.36.1 h1:XbL/EMj8K2aJpJtePmqUyQMsM0D4QI2pvl7YKJ20FTY= k8s.io/api v0.36.1/go.mod h1:KOWo4ey3TINlXjeHVuwB3i+tXXnu+UcwFBHlI/9dvEo= -k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0= -k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug= +k8s.io/apiextensions-apiserver v0.36.1 h1:6JfYmPUsuUIHuN+3QxutXYWj492RqF5fBSx67GYK5Ks= +k8s.io/apiextensions-apiserver v0.36.1/go.mod h1:pLzZin90riwisdzKwv/GoTwENooytoIx5zWJb4Hkby8= k8s.io/apimachinery v0.36.1 h1:G63Gjx2W+q0YD+72Vo8oY0nDnePVwnuzTmmy5ENrVSA= k8s.io/apimachinery v0.36.1/go.mod h1:ibYOR00vW/I1kzvi5SF0dRuJ52BvKtfvRdOn35GPQ+8= -k8s.io/apiserver v0.36.0 h1:Jg5OFAENUACByUCg15CmhZAYrr5ZyJ+jodyA1mHl3YE= -k8s.io/apiserver v0.36.0/go.mod h1:mHvwdHf+qKEm+1/hYm756SV+oREOKSPnsjagOpx6Vho= +k8s.io/apiserver v0.36.1 h1:iMS5V+rPUertv5P9RaqJgmHHTuh4quWpoxchvMUY+JY= +k8s.io/apiserver v0.36.1/go.mod h1:Cby1PbLWztu0GDOxoO6iFOyyqIsziHNEW+w9zVQ22Kw= k8s.io/client-go v0.36.1 h1:FN/K8QIT2CEDt+2WB2HnWrUANZ50AP5GII43/SP2JR0= k8s.io/client-go v0.36.1/go.mod h1:s6rAnCtTGYDQnpNjEhSaISV+2O8jwruZ6m3QOYBFbtU= k8s.io/component-base v0.36.1 h1:iG6GsELftXqTNG9HG6kiVjatSgAw1sf5pJ6R5a6N0kA= @@ -307,8 +307,8 @@ k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= -k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= +k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= diff --git a/pkg/agent/config.go b/pkg/agent/config.go index 45dae0b0..1c8e7335 100644 --- a/pkg/agent/config.go +++ b/pkg/agent/config.go @@ -41,8 +41,9 @@ type Config struct { // Server is the base URL for the Preflight server. It defaults to // https://preflight.jetstack.io in Jetstack Secure OAuth and Jetstack // Secure API Token modes, and https://api.venafi.cloud in Venafi Cloud Key - // Pair Service Account mode. It is ignored in Venafi Cloud VenafiConnection - // mode and in MachineHub mode. + // Pair Service Account mode. It is ignored in VenafiConnection mode (the + // backend URL is taken from the VenafiConnection resource), in NGTS mode + // (use --tsg-id or --ngts-server-url instead) and in MachineHub mode. Server string `yaml:"server"` // OrganizationID is only used in Jetstack Secure OAuth and Jetstack Secure @@ -160,7 +161,9 @@ type AgentCmdFlags struct { APIToken string // VenConnName (--venafi-connection) is the name of the VenafiConnection - // resource to use. Using this flag will enable Venafi Connection mode. + // resource to use. Using this flag will enable VenafiConnection mode. The + // upload backend (Venafi Cloud or NGTS) is selected by the spec of the + // referenced VenafiConnection resource. VenConnName string // VenConnNS (--venafi-connection-namespace) is the namespace of the @@ -183,8 +186,13 @@ type AgentCmdFlags struct { // Prometheus (--enable-metrics) enables the Prometheus metrics server. Prometheus bool - // NGTSMode (--ngts) turns on the NGTS mode. The agent will authenticate - // using key pair authentication and send data to NGTS endpoints. + // NGTSMode (--ngts) turns on the NGTS keypair mode. The agent will + // authenticate to the NGTS endpoint using an NGTS built-in service account + // key pair (--client-id and --private-key-path). + // + // To authenticate to NGTS through a VenafiConnection resource instead, use + // --venafi-connection (without --ngts) and point it at a VenafiConnection + // whose spec selects the NGTS backend. NGTSMode bool // TSGID (--tsg-id) is the TSG (Tenant Service Group) ID for NGTS mode. @@ -291,8 +299,10 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) { &cfg.VenConnName, "venafi-connection", "", - "Turns on the "+string(VenafiCloudVenafiConnection)+" mode. "+ - "This flag configures the name of the VenafiConnection to be used.", + "Turns on the "+string(VenafiConnection)+" mode. The upload backend (Venafi Cloud "+ + "or NGTS) is selected by the spec of the referenced VenafiConnection "+ + "resource. This flag configures the name of the VenafiConnection to "+ + "be used.", ) c.PersistentFlags().StringVar( &cfg.VenConnNS, @@ -352,9 +362,10 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) { &cfg.NGTSMode, "ngts", false, - "Enables NGTS mode. The agent will authenticate using key pair authentication and send data to NGTS endpoints. "+ + "Enables NGTS keypair mode. The agent will authenticate to NGTS using an NGTS built-in service account key pair. "+ "Must be used with --private-key-path and exactly one of --tsg-id or --ngts-server-url. "+ - "--client-id is optional if provided in the credentials secret.", + "--client-id is optional if provided in the credentials secret. "+ + "To authenticate to NGTS through a VenafiConnection resource instead, use --venafi-connection without this flag.", ) c.PersistentFlags().StringVar( &cfg.TSGID, @@ -386,13 +397,13 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) { type OutputMode string const ( - JetstackSecureOAuth OutputMode = "Jetstack Secure OAuth" - JetstackSecureAPIToken OutputMode = "Jetstack Secure API Token" - VenafiCloudKeypair OutputMode = "Venafi Cloud Key Pair Service Account" - VenafiCloudVenafiConnection OutputMode = "Venafi Cloud VenafiConnection" - LocalFile OutputMode = "Local File" - MachineHub OutputMode = "MachineHub" - NGTS OutputMode = "NGTS" + JetstackSecureOAuth OutputMode = "Jetstack Secure OAuth" + JetstackSecureAPIToken OutputMode = "Jetstack Secure API Token" + VenafiCloudKeypair OutputMode = "Venafi Cloud Key Pair Service Account" + VenafiConnection OutputMode = "VenafiConnection" + LocalFile OutputMode = "Local File" + MachineHub OutputMode = "MachineHub" + NGTS OutputMode = "NGTS" ) // The command-line flags and the config file and some environment variables are @@ -411,7 +422,9 @@ type CombinedConfig struct { ClusterID string // Used by JetstackSecureOAuth, JetstackSecureAPIToken, and - // VenafiCloudKeypair. Ignored in VenafiCloudVenafiConnection mode. + // VenafiCloudKeypair. Ignored in VenafiConnection mode (the + // backend URL is taken from the VenafiConnection resource) and in NGTS + // mode (set via --tsg-id or --ngts-server-url instead). Server string // JetstackSecureOAuth and JetstackSecureAPIToken modes only. @@ -434,11 +447,11 @@ type CombinedConfig struct { // false (default) = certs are owned by this cluster's tenant. ClaimableCerts bool - // VenafiCloudVenafiConnection mode only. + // VenafiConnection mode only. VenConnName string VenConnNS string - // VenafiCloudKeypair and VenafiCloudVenafiConnection modes only. + // Applied to all data gatherers regardless of OutputMode. ExcludeAnnotationKeysRegex []*regexp.Regexp ExcludeLabelKeysRegex []*regexp.Regexp @@ -490,7 +503,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) reason = "--client-id and --private-key-path were specified" keysAndValues = []any{"clientID", flags.ClientID, "privateKeyPath", flags.PrivateKeyPath} case flags.VenConnName != "": - mode = VenafiCloudVenafiConnection + mode = VenafiConnection reason = "--venafi-connection was specified" keysAndValues = []any{"venConnName", flags.VenConnName} case flags.APIToken != "": @@ -513,7 +526,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) "To enable one of the output modes, you can:\n" + " - 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" + " - Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the " + string(VenafiCloudKeypair) + " mode.\n" + - " - Use --venafi-connection for the " + string(VenafiCloudVenafiConnection) + " mode.\n" + + " - Use --venafi-connection for the " + string(VenafiConnection) + " mode (the upload backend - Venafi Cloud or NGTS - is selected by the VenafiConnection resource).\n" + " - Use --credentials-file alone if you want to use the " + string(JetstackSecureOAuth) + " mode.\n" + " - Use --api-token if you want to use the " + string(JetstackSecureAPIToken) + " mode.\n" + " - Use --machine-hub if you want to use the " + string(MachineHub) + " mode.\n" + @@ -544,9 +557,13 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) errs = multierror.Append(errs, fmt.Errorf("--machine-hub cannot be used with --ngts. These are mutually exclusive modes.")) } - // Error if VenafiConnection mode flags are used + // Error if VenafiConnection mode flags are used. The --ngts flag + // selects NGTS keypair auth; to authenticate to NGTS through a + // VenafiConnection resource, drop --ngts and use --venafi-connection + // on its own (the agent picks the NGTS backend from the + // VenafiConnection's spec). if flags.VenConnName != "" { - errs = multierror.Append(errs, fmt.Errorf("--venafi-connection cannot be used with --ngts. Use --client-id and --private-key-path instead.")) + errs = multierror.Append(errs, fmt.Errorf("--venafi-connection cannot be used with --ngts. Either drop --ngts to authenticate to NGTS through a VenafiConnection resource, or drop --venafi-connection and use --client-id and --private-key-path for NGTS keypair auth.")) } // Error if Jetstack Secure OAuth mode flags are used @@ -602,12 +619,14 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) case !hasServerField && !hasEndpointField: server = "https://preflight.jetstack.io" if res.OutputMode == VenafiCloudKeypair { - // The VenafiCloudVenafiConnection mode doesn't need a server. + // VenafiConnection mode (VCP or NGTS) takes its server from + // the VenafiConnection resource and doesn't need one here. server = client.VenafiCloudProdURL } if res.OutputMode == NGTS { - // In NGTS mode, use NGTSServerURL if provided, otherwise we'll use a default - // (which will be determined when creating the client) + // In NGTS keypair mode, use NGTSServerURL if provided, otherwise + // we'll use a default (derived from --tsg-id at client construction + // time). server = res.NGTSServerURL } } @@ -633,8 +652,8 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) errs = multierror.Append(errs, fmt.Errorf("server %q is not a valid URL", server)) } - if res.OutputMode == VenafiCloudVenafiConnection && server != "" { - log.Info(fmt.Sprintf("ignoring the server field specified in the config file. In %s mode, this field is not needed.", VenafiCloudVenafiConnection)) + if res.OutputMode == VenafiConnection && server != "" { + log.Info(fmt.Sprintf("ignoring the server field specified in the config file. In %s mode, this field is not needed.", VenafiConnection)) server = "" } @@ -658,7 +677,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) } uploadPath = cfg.VenafiCloud.UploadPath - case VenafiCloudVenafiConnection: + case VenafiConnection: // The venafi-cloud.upload_path was initially meant to let users // configure HTTP proxies, but it has never been used since HTTP // proxies don't rewrite paths. Thus, we've disabled the ability to @@ -706,7 +725,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) } clusterName = cfg.ClusterName // cluster_id and organization_id were already validated to not be present in NGTS mode - case VenafiCloudKeypair, VenafiCloudVenafiConnection: + case VenafiCloudKeypair, VenafiConnection: // For backwards compatibility, use the agent config's `cluster_id` as // ClusterName if `cluster_name` is not set. if cfg.ClusterName == "" && cfg.ClusterID == "" { @@ -795,7 +814,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) var err error installNS, err = getInClusterNamespace() if err != nil { - if res.OutputMode == VenafiCloudVenafiConnection { + if res.OutputMode == VenafiConnection { errs = multierror.Append(errs, fmt.Errorf("could not guess which namespace the agent is running in: %w", err)) } } @@ -804,7 +823,7 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) } // Validation of --venafi-connection and --venafi-connection-namespace. - if res.OutputMode == VenafiCloudVenafiConnection { + if res.OutputMode == VenafiConnection { res.VenConnName = flags.VenConnName venConnNS := flags.VenConnNS if flags.VenConnNS == "" { @@ -933,7 +952,7 @@ func validateCredsAndCreateClient(log logr.Logger, flagCredentialsPath, flagClie // arbitrary value. uploaderID := "no" - // We don't do this for the VenafiCloudVenafiConnection mode because + // We don't do this for the VenafiConnection mode because // the upload_path field is ignored in that mode. log.Info("Loading upload_path from \"venafi-cloud\" configuration.") @@ -942,7 +961,7 @@ func validateCredsAndCreateClient(log logr.Logger, flagCredentialsPath, flagClie if err != nil { errs = multierror.Append(errs, err) } - case VenafiCloudVenafiConnection: + case VenafiConnection: var restCfg *rest.Config restCfg, err := kubeconfig.LoadRESTConfig("") if err != nil { diff --git a/pkg/agent/config_test.go b/pkg/agent/config_test.go index 364661c6..d4460251 100644 --- a/pkg/agent/config_test.go +++ b/pkg/agent/config_test.go @@ -197,7 +197,7 @@ func Test_ValidateAndCombineConfig(t *testing.T) { no output mode specified. To enable one of the output modes, you can: - 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). - Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the Venafi Cloud Key Pair Service Account mode. - - Use --venafi-connection for the Venafi Cloud VenafiConnection mode. + - Use --venafi-connection for the VenafiConnection mode (the upload backend - Venafi Cloud or NGTS - is selected by the VenafiConnection resource). - Use --credentials-file alone if you want to use the Jetstack Secure OAuth mode. - Use --api-token if you want to use the Jetstack Secure API Token mode. - Use --machine-hub if you want to use the MachineHub mode. @@ -585,15 +585,15 @@ func Test_ValidateAndCombineConfig(t *testing.T) { withCmdLineFlags("--venafi-connection", "venafi-components")) require.NoError(t, err) assert.Equal(t, testutil.Undent(` - INFO Output mode selected venConnName="venafi-components" mode="Venafi Cloud VenafiConnection" reason="--venafi-connection was specified" - INFO ignoring the server field specified in the config file. In Venafi Cloud VenafiConnection mode, this field is not needed. + INFO Output mode selected venConnName="venafi-components" mode="VenafiConnection" reason="--venafi-connection was specified" + INFO ignoring the server field specified in the config file. In VenafiConnection mode, this field is not needed. INFO Using cluster_id as cluster_name for backwards compatibility clusterID="legacy cluster_id as cluster name" INFO Using period from config period="1h0m0s" `), gotLogs.String()) assert.Equal(t, CombinedConfig{ Period: 1 * time.Hour, ClusterName: "legacy cluster_id as cluster name", - OutputMode: VenafiCloudVenafiConnection, + OutputMode: VenafiConnection, VenConnName: "venafi-components", VenConnNS: "venafi", InstallNS: "venafi", @@ -620,14 +620,14 @@ func Test_ValidateAndCombineConfig(t *testing.T) { ) require.NoError(t, err) assert.Equal(t, testutil.Undent(` - INFO Output mode selected venConnName="venafi-components" mode="Venafi Cloud VenafiConnection" reason="--venafi-connection was specified" - INFO ignoring the server field specified in the config file. In Venafi Cloud VenafiConnection mode, this field is not needed. - INFO ignoring the venafi-cloud.upload_path field in the config file. In Venafi Cloud VenafiConnection mode, this field is not needed. - INFO ignoring the venafi-cloud.uploader_id field in the config file. This field is not needed in Venafi Cloud VenafiConnection mode. - INFO Ignoring the cluster_id field in the config file. This field is not needed in Venafi Cloud VenafiConnection mode. + INFO Output mode selected venConnName="venafi-components" mode="VenafiConnection" reason="--venafi-connection was specified" + INFO ignoring the server field specified in the config file. In VenafiConnection mode, this field is not needed. + INFO ignoring the venafi-cloud.upload_path field in the config file. In VenafiConnection mode, this field is not needed. + INFO ignoring the venafi-cloud.uploader_id field in the config file. This field is not needed in VenafiConnection mode. + INFO Ignoring the cluster_id field in the config file. This field is not needed in VenafiConnection mode. INFO Using period from config period="1h0m0s" `), gotLogs.String()) - assert.Equal(t, VenafiCloudVenafiConnection, got.OutputMode) + assert.Equal(t, VenafiConnection, got.OutputMode) assert.IsType(t, &client.VenConnClient{}, gotCl) }) @@ -642,7 +642,20 @@ func Test_ValidateAndCombineConfig(t *testing.T) { `)), withCmdLineFlags("--venafi-connection", "venafi-components")) require.NoError(t, err) - assert.Equal(t, VenafiCloudVenafiConnection, got.OutputMode) + assert.Equal(t, VenafiConnection, got.OutputMode) + }) + + t.Run("venafi-cloud-workload-identity-auth: --venafi-cloud is tolerated alongside --venafi-connection for backwards compatibility with older rendered charts", func(t *testing.T) { + t.Setenv("POD_NAMESPACE", "venafi") + t.Setenv("KUBECONFIG", withFile(t, fakeKubeconfig)) + got, _, err := ValidateAndCombineConfig(discardLogs(), + withConfig(testutil.Undent(` + period: 1h + cluster_name: cluster-1 + `)), + withCmdLineFlags("--venafi-connection", "venafi-components", "--venafi-cloud")) + require.NoError(t, err) + assert.Equal(t, VenafiConnection, got.OutputMode) }) const arkUsername = "cluster-1-region-1-cloud-1@cyberark.cloud.123456" @@ -864,7 +877,7 @@ func Test_ValidateAndCombineConfig_VenafiConnection(t *testing.T) { _, _, err := ValidateAndCombineConfig(discardLogs(), Config{Server: "http://should-be-ignored", Period: 1 * time.Hour}, AgentCmdFlags{VenConnName: "venafi-components", InstallNS: "venafi"}) - assert.EqualError(t, err, "1 error occurred:\n\t* cluster_name or cluster_id is required in Venafi Cloud VenafiConnection mode\n\n") + assert.EqualError(t, err, "1 error occurred:\n\t* cluster_name or cluster_id is required in VenafiConnection mode\n\n") }) t.Run("the server field is ignored when VenafiConnection is used", func(t *testing.T) { diff --git a/pkg/client/client_oauth.go b/pkg/client/client_oauth.go index 5cc1e64f..b7ad93ea 100644 --- a/pkg/client/client_oauth.go +++ b/pkg/client/client_oauth.go @@ -159,8 +159,8 @@ func (c *OAuthClient) post(ctx context.Context, path string, body io.Reader) (*h return nil, err } + req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") - version.SetUserAgent(req) if len(token.bearer) > 0 { diff --git a/pkg/client/client_venconn.go b/pkg/client/client_venconn.go index 9ce0c86b..9a6f28e0 100644 --- a/pkg/client/client_venconn.go +++ b/pkg/client/client_venconn.go @@ -13,8 +13,10 @@ import ( "time" venapi "github.com/jetstack/venafi-connection-lib/api/v1alpha1" - "github.com/jetstack/venafi-connection-lib/chain/sources/venafi" + "github.com/jetstack/venafi-connection-lib/connection_details" + "github.com/jetstack/venafi-connection-lib/sources/venafi" "github.com/jetstack/venafi-connection-lib/venafi_client" + "github.com/microcosm-cc/bluemonday" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -137,17 +139,25 @@ func (c *VenConnClient) PostDataReadingsWithOptions(ctx context.Context, reading if err != nil { return fmt.Errorf("while loading the VenafiConnection %s/%s: %w", c.venConnNS, c.venConnName, err) } - if details.TPP != nil { - return fmt.Errorf(`VenafiConnection %s/%s: the agent cannot be used with TPP`, c.venConnNS, c.venConnName) - } - if details.VCP != nil && details.VCP.APIKey != "" { + server := details.ServerDetails() + switch server.BackendAuth { + case connection_details.VCPAccessToken, connection_details.NGTSAccessToken: + // Supported. + case connection_details.TPPAccessToken: + return fmt.Errorf(`VenafiConnection %s/%s: the agent does not support the TPP backend`, c.venConnNS, c.venConnName) + case connection_details.DistributedIssuerAccessToken: + return fmt.Errorf(`VenafiConnection %s/%s: the agent does not support the Distributed Issuer backend`, c.venConnNS, c.venConnName) + case connection_details.VCPAPIKey: // Although it is technically possible to use an API key, we have // decided to not allow it as it isn't recommended and will eventually // be phased out. - return fmt.Errorf(`VenafiConnection %s/%s: the agent cannot be used with an API key`, c.venConnNS, c.venConnName) + return fmt.Errorf(`VenafiConnection %s/%s: the agent does not support API key authentication with the VCP backend`, c.venConnNS, c.venConnName) + default: + return fmt.Errorf(`VenafiConnection %s/%s: the agent does not support backend auth %q`, c.venConnNS, c.venConnName, server.BackendAuth) } - if details.VCP == nil || details.VCP.AccessToken == "" { - return fmt.Errorf(`programmer mistake: VenafiConnection %s/%s: TPPAccessToken is empty in the token returned by connHandler.Get: %v`, c.venConnNS, c.venConnName, details) + token := details.Credential() + if token == "" { + return fmt.Errorf(`programmer mistake: VenafiConnection %s/%s: access token is empty in the connection details returned by connHandler.Get`, c.venConnNS, c.venConnName) } payload := api.DataReadingsPost{ @@ -160,9 +170,10 @@ func (c *VenConnClient) PostDataReadingsWithOptions(ctx context.Context, reading return err } + uploadURL := fullURL(server.BaseURL, "/v1/tlspk/upload/clusterdata/no") klog.FromContext(ctx).V(2).Info( "uploading data readings", - "url", fullURL(details.VCP.URL, "/v1/tlspk/upload/clusterdata/no"), + "url", uploadURL, "cluster_name", opts.ClusterName, "data_readings_count", len(readings), "data_size_bytes", len(data), @@ -171,21 +182,30 @@ func (c *VenConnClient) PostDataReadingsWithOptions(ctx context.Context, reading // The path parameter "no" is a dummy parameter to make the Venafi Cloud // backend happy. This parameter, named `uploaderID` in the backend, is not // actually used by the backend. - req, err := http.NewRequestWithContext(ctx, http.MethodPost, fullURL(details.VCP.URL, "/v1/tlspk/upload/clusterdata/no"), bytes.NewReader(data)) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, bytes.NewReader(data)) if err != nil { return err } + req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", details.VCP.AccessToken)) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) version.SetUserAgent(req) - q := req.URL.Query() - q.Set("name", opts.ClusterName) + query := req.URL.Query() + stripHTML := bluemonday.StrictPolicy() + if opts.ClusterName != "" { + query.Add("name", stripHTML.Sanitize(opts.ClusterName)) + } if opts.ClusterDescription != "" { - q.Set("description", base64.RawURLEncoding.EncodeToString([]byte(opts.ClusterDescription))) + query.Add("description", base64.RawURLEncoding.EncodeToString([]byte(stripHTML.Sanitize(opts.ClusterDescription)))) } - req.URL.RawQuery = q.Encode() + if isNGTS := server.BackendAuth == connection_details.NGTSAccessToken; isNGTS && opts.ClaimableCerts { + // The TLSPK backend reads "certOwnership=unassigned" — this is the backend contract. + query.Add("certOwnership", "unassigned") + } + + req.URL.RawQuery = query.Encode() res, err := c.Client.Do(req) if err != nil { diff --git a/pkg/client/client_venconn_test.go b/pkg/client/client_venconn_test.go index 6b9e14a4..adfb633a 100644 --- a/pkg/client/client_venconn_test.go +++ b/pkg/client/client_venconn_test.go @@ -156,7 +156,64 @@ func TestVenConnClient_PostDataReadingsWithOptions(t *testing.T) { // PostDataReadingsWithOptions failed, but Get succeeded; that's why the // condition says the VenafiConnection is ready. expectReadyCondMsg: "Generated a new token", - expectErr: "VenafiConnection error-when-the-apikey-field-is-used/venafi-components: the agent cannot be used with an API key", + expectErr: "VenafiConnection error-when-the-apikey-field-is-used/venafi-components: the agent does not support API key authentication with the VCP backend", + })) + t.Run("error when the distributedIssuer field is used", run_TestVenConnClient_PostDataReadingsWithOptions(ctx, restconf, kclient, testcase{ + // The Firefly / Distributed Issuer backend reaches the + // `connection_details.DistributedIssuerAccessToken` branch, which the + // agent rejects since it only supports VCP and NGTS upload backends. + given: testutil.Undent(` + apiVersion: jetstack.io/v1alpha1 + kind: VenafiConnection + metadata: + name: venafi-components + namespace: TEST_NAMESPACE + spec: + distributedIssuer: + url: FAKE_TPP_URL + accessToken: + - secret: + name: accesstoken + fields: [accesstoken] + allowReferencesFrom: + matchExpressions: + - {key: kubernetes.io/metadata.name, operator: In, values: [venafi]} + --- + apiVersion: v1 + kind: Secret + metadata: + name: accesstoken + namespace: TEST_NAMESPACE + stringData: + accesstoken: VALID_ACCESS_TOKEN + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: venafi-connection-accesstoken-reader + namespace: TEST_NAMESPACE + rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + resourceNames: ["accesstoken"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: venafi-connection-accesstoken-reader + namespace: TEST_NAMESPACE + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: venafi-connection-accesstoken-reader + subjects: + - kind: ServiceAccount + name: venafi-connection + namespace: venafi + `), + expectReadyCondMsg: "Generated a new token", + expectErr: "VenafiConnection error-when-the-distributedissuer-field-is-used/venafi-components: the agent does not support the Distributed Issuer backend", })) t.Run("error when the tpp field is used", run_TestVenConnClient_PostDataReadingsWithOptions(ctx, restconf, kclient, testcase{ // IMPORTANT: The user may think they can use 'tpp', spend time @@ -214,7 +271,7 @@ func TestVenConnClient_PostDataReadingsWithOptions(t *testing.T) { namespace: venafi `), expectReadyCondMsg: "Generated a new token", - expectErr: "VenafiConnection error-when-the-tpp-field-is-used/venafi-components: the agent cannot be used with TPP", + expectErr: "VenafiConnection error-when-the-tpp-field-is-used/venafi-components: the agent does not support the TPP backend", })) }