venafi-oauth-helper
Configure Venafi TPP
This step may need to be performed by a Venafi TPP Administrator.
- In the API Integrations page (Configuration -> API Application Integration), create a new API Integration.
- Set the name to anything to like (e.g jetstack-cert-manager-app)
- For the permissions, select read, manage, revoke certificates
- IMPORTANT - Set the application id to cert-manager.io
- In the Access Limits, select Configure and set the Grant Expiration to number of days you want the refresh token to be valid (For e.g 730 days)
- Select the Token Refresh to enabled
- Set the Token expiration to a shorter period to number of days you want (for e.g. 1 day).
- After Saving, authorize the Venafi TPP user(s) who will have access to the cert-manager.io application by clicking Edit Access and adding the user.
The above step ensures that the user who is authorized to access cert-manager.io application has the ability to request an access token. This is a one time step that needs to be completed by the Venafi Administrator.
⚠️ If the Application ID is different to the default: cert-manager.io, you MUST also configure venafi-oauth-helper to use that Application ID using the --client-id command line option.
ℹ️ If cert-manager is already in use and if there is an Issuer configured to use Venafi TPP with access-token credentials, there will already be an application integration with the ID cert-manager. You may use that application integration as long as you enable Refresh Token and update the Grant and Token expiration periods.
ℹ️ In future versions of TPP, the application integration may be pre-defined, in which case you can use that.
🔰 Read about Creating API application integrations in the TPP documentation.
🔰 Read about Setting up token authentication in the TPP documentation.
Configure venafi-oauth-helper
Create a Bootstrap Secret
venafi-oauth-helper can be bootstrapped using refresh-token, username-password, or client-certificate credentials.
For an Issuer the bootstrap Secret must be in the same namespace as the Issuer.
For a ClusterIssuer the bootstrap Secret must be in the --cluster-resource-namespace. By default this is the same namespace as the venafi-oauth-helper Pod (cert-manager) but it may be different if you have installed venafi-oauth-helper in a different namespace, of if you have changed the --cluster-resource-namespace command line option.
...using a refresh-token
This is the most secure bootstrap method because you will not have to store the username-password or client-certificate in a Secret in the Kubernetes cluster. These sensitive credentials can be stored outside the cluster and need only be accessed when deploying the venafi-oauth-helper.
The disadvantage of this configuration is that if the refresh-token reaches its time limit, or if a new refresh-token is not successfully saved after rotation, or if the refresh-token is revoked, then the venafi-oauth-helper will cease to function until a new refresh-token is generated and saved to the Kubernetes Secret by an administrator.
⚠️ The refresh-token has a fixed expiry time. The expiry time of each rotated refresh-token will be the same as the initial bootstrap refresh-token from which they are derived. So you will need to use your username-password or client-certificate to generate a new bootstrap refresh-token before the current refresh-token expires. You should automate this if possible.
⚠️ The access-token / refresh-token may be revoked at any time by the TPP administrator, which will cause venafi-oauth-helper to stop renewing access-tokens, if using the refresh-token bootstrap method. So you should setup an alert which fires when venafi-oauth-helper logs the error: {"level":"error", "msg":"Giving up",...}, and have a process for generating a new bootstrap refresh-token, which will fix the error.
Create the refresh-token
If you do not have credentials to the Venafi Platform, your Venafi administrator will need to run this command :
vcert getcred --username REPLACE_WITH_VENAFI_TPP_USER \--password REPLACE_WITH_VENAFI_TPP_PASSWORD \-u https://REPLACE_WITH_VENAFI_TPP_HOSTNAME/vedsdk \--client-id cert-manager.io \--scope "certificate:manage,revoke" \--format json > /tmp/token
⚠️ The client-id in the command above MUST match the client-id used by venafi-oauth-helper, and MUST match the Application ID created in the Common Configuration section above. The default client-id is cert-manager.io but you can change it using the command line option: --client-id.
🔰 To know more about the OAuth tokens in TPP, see Obtaining an Authorization Token in the VCert documentation.
Save the refresh-token to a Kubernetes Secret
In this step, we will create a bootstrap secret using the refresh-token that we retrieved in the previous step.
ℹ️ The refresh token is retrieved from the /tmp/token using jq. If jq doesn't work on your machine, no worries, just replace $(jq -r .refresh_token < /tmp/token) with the actual refresh-token retrieved in previous step.
kubectl apply -f- <<EOFapiVersion: v1kind: Secretmetadata:name: issuer-1-credentials-voh-bootstrapnamespace: ISSUER_NAMESPACE # ⚠ or CLUSTER_RESOURCE_NAMESPACE when using a ClusterIssuerstringData:refresh-token: $(jq -r .refresh_token < /tmp/token)refresh-token-expires: $(jq -r ".refresh_until|todate" < /tmp/token)EOF
...using a username-password
Alternatively you can create a bootstrap secret containing a username-password, and the advantage of this is that venafi-oauth-helper can always request a new refresh-token, even if the last live refresh-token becomes invalid.
This is less secure because your username-password, which has greater privileges than a refresh-token, are now stored in the Kubernetes Cluster and therefore more exposed to accidental leakage and malicious use.
Update the username-password and apply the YAML:
kubectl apply -f- <<EOFapiVersion: v1kind: Secretmetadata:name: issuer-1-credentials-voh-bootstrapnamespace: ISSUER_NAMESPACE # ⚠ or CLUSTER_RESOURCE_NAMESPACE when using a ClusterIssuerstringData:username: REPLACE_WITH_VENAFI_TPP_USERpassword: REPLACE_WITH_VENAFI_TPP_PASSWORDEOF
...using a client-certificate
In this configuration, you store a client-certificate in the bootstrap credentials Secret.
This is less secure, because your client-certificate, which may have greater privileges than a refresh-token, is now stored in the Kubernetes Cluster and therefore more exposed to accidental leakage and malicious use.
kubectl create secret generic \issuer-1-credentials-voh-bootstrap \--namespace=ISSUER_NAMESPACE \ # ⚠ or CLUSTER_RESOURCE_NAMESPACE when using a ClusterIssuer--from-file=p12-archive='/path/to/pfx/file.pfx' \--from-literal=p12-password='PFX_DECRYPTION_PASSWORD'
Annotate the Bootstrap Secret
Annotate the Secret so that venafi-oauth-helper can match the bootstrap Secret to your Issuer:
kubectl annotate secret issuer-1-credentials-voh-bootstrap \voh.jetstack.io/issuer=issuer-1 \--namespace=<NAMESPACE OF YOUR ISSUER RESOURCE>
⚠ For a ClusterIssuer use the annotation voh.jetstack.io/cluster-issuer.
venafi-oauth-helper will immediately use this bootstrap credential to get an access-token and a new live refresh-token and these will be stored to separate Secret resources. Thereafter, the live refresh-token will be used to renew the access-token. If the live refresh-token fails, then venafi-oauth-helper will automatically try using the bootstrap credential again to generate a new refresh-token, but this will only work if you use a username-password or a client-certificate for the bootstrap credential.
⚠ Remember that a refresh-token can only be used once, so if you used a refresh-token as the bootstrap credential, TPP will have invalidated after it was first used. If the live refresh-token stops working you will need to manually create a new refresh-token and save it to the bootstrap credential Secret.
Configure cert-manager
Create a cert-manager Issuer (or ClusterIssuer), referencing a Secret, but do not create the Secret.
⚠ The issuer refers to a credentialsRef that we did not create. That is intentional. It is the job of venafi-oauth-helper to create the secret with access-token required to access Venafi TPP.
kubectl apply -f- <<EOFapiVersion: cert-manager.io/v1kind: Issuermetadata:name: issuer-1spec:venafi:zone: "REPLACE_WITH_YOUR_VENAFI_POLICY_FOLDER"tpp:url: https://REPLACE_WITH_VENAFI_TPP_HOST/vedsdkcaBundle: REPLACE_WITH_BASE64_ENCODED_CERT_CHAIN_TO_ACCESS_VENAFIcredentialsRef:name: issuer-1-credentialsEOF
Check to see the status of the issuer. It should be ready.
kubectl get issuer issuer-1
kubectl describe issuer issuer-1
Verify the configuration
Request a certificate
kubectl apply -f- <<EOFapiVersion: cert-manager.io/v1kind: Certificatemetadata:name: test-certificatespec:secretName: test-certificateprivateKey:rotationPolicy: AlwaysdnsNames:- test.example.comcommonName: test.example.comissuerRef:name: issuer-1kind: IssuerEOF
A certificate should be issued successfully.