Auto-Rotate Kubernetes Secrets

Sync CyberArk secrets to Kubernetes and auto-restart pods on rotation.

Introduction

30 Second Summary

Every application has secrets. Database passwords, API keys, encryption tokens. When one of those secrets needs to change, someone has to update every system that uses it. Miss one, and your app goes down.

In this project, you will build an automated secrets rotation pipeline using CyberArk Secrets Provider for Kubernetes and Stakater Reloader. You'll change a secret in Conjur Cloud and watch it automatically propagate to your Kubernetes application pods with zero manual intervention.

What You'll Build

A complete secrets injection and auto-rotation pipeline running on a local Minikube cluster that syncs secrets from CyberArk Conjur Cloud into Kubernetes Secrets and automatically restarts application pods when those secrets change.

By the end of this project, you'll have:

  • A Golden ConfigMap and application namespace configured with JWT authentication for secure workload identity.
  • Conjur Cloud policy defining a workload host, secrets, and access grants for your Kubernetes application.
  • A Secrets Provider Helm deployment with Stakater Reloader enabled, delivering a live end-to-end secret rotation you can verify from inside a running pod.
  • Secret Mission: Configure targeted restart annotations for multi-secret scenarios and set up health monitoring with sentinel file liveness probes.

Are there any prerequisites?

This project requires an existing CyberArk Secrets Manager SaaS tenant with admin access. You also need macOS with Minikube and Docker installed. Step 1 walks you through installing Helm and the Conjur CLI.

If you don't yet have a JWT authenticator configured for your Kubernetes cluster, Step 2 covers that setup. If you already have one, you can skip straight to Step 3.

Set Up Your Local Environment

Before you can deploy the secrets rotation pipeline, your local machine needs the right tools in place. Minikube gives you a local Kubernetes cluster to work with. Helm handles the chart-based deployments. The Conjur CLI connects you to your CyberArk Secrets Manager SaaS tenant.

In this step, you will start Minikube, install Helm and the CyberArk Helm charts repository, and authenticate to your Conjur Cloud tenant.

In this step, get ready to:
  • Start Minikube and verify your cluster is running.
  • Install Helm and add the CyberArk Helm charts repository.
  • Install the Conjur CLI and authenticate to your Secrets Manager SaaS tenant.
Start Minikube and verify the Docker driver

Minikube runs a single-node Kubernetes cluster inside a Docker container on your Mac. Starting it with the Docker driver is the fastest way to get a cluster running locally.

  • Open your terminal by pressing Cmd+Space (macOS) and typing Terminal.
  • Start your Minikube cluster with the Docker driver by running this command:
minikube start --driver=docker

What does this command do?

This command tells Minikube to create and start a local Kubernetes cluster using Docker as the underlying container runtime. The --driver=docker flag ensures Minikube runs the cluster inside a Docker container instead of a virtual machine.

After a minute or so, you should see output ending with a line like Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default.

  • Confirm that kubectl can talk to your new cluster by running:
kubectl get nodes

You should see your minikube node listed with a STATUS of Ready.

Minikube not starting?

Make sure Docker Desktop is running before you run minikube start. The Docker driver requires a running Docker daemon.

If you see a timeout or crash loop error, try deleting the cluster and starting fresh:

minikube delete
minikube start --driver=docker

help me troubleshoot Minikube startup errors with the Docker driver on macOS

Install Helm and add the CyberArk Helm charts repository

Helm is a package manager for Kubernetes. The CyberArk Secrets Provider and its supporting charts are distributed through the CyberArk Helm repository.

  • Check if Helm is already installed by running:
helm version

✔️ I see a version number

Helm is already installed. Skip ahead to the next bullet to add the CyberArk repo.

ⓧ Command not found

Helm is not installed yet. No worries.

  • Install Helm using Homebrew by running:
brew install helm
  • After the installation finishes, verify it worked by running:
helm version

You should see a version string printed in your terminal.

brew command not found?

Homebrew might not be installed on your machine. Visit brew.sh and follow the install instructions, then try brew install helm again.

help me install Homebrew on macOS so I can install Helm

  • Add the CyberArk Helm charts repository by running:
helm repo add cyberark https://cyberark.github.io/helm-charts
  • Update the repository index to pull in the latest chart versions by running:
helm repo update

You should see "cyberark" has been added to your repositories after the add command, and a successful update message after the update command.

Why add a Helm repo?

Helm repos are like package registries for Kubernetes charts. Adding the CyberArk repo gives Helm access to the Secrets Provider chart, the cluster preparation chart, and the namespace preparation chart you will use in later steps.

Seeing a network error?

Make sure you have an active internet connection. The helm repo add command needs to reach https://cyberark.github.io/helm-charts to download the chart index.

help me troubleshoot Helm repo add failing with a network error

Install the Conjur CLI and log in to your tenant

The Conjur CLI lets you manage policies, secrets, and authenticators on your CyberArk Secrets Manager SaaS tenant directly from the terminal.

  • Check if the Conjur CLI is already installed by running:
conjur --version

✔️ I see a version number

The Conjur CLI is already installed. Skip ahead to the initialization step below.

ⓧ Command not found

The Conjur CLI is not installed yet. You can install it with Homebrew using the CyberArk tools tap.

  • Add the CyberArk Homebrew tap and install the CLI by running these commands:
# Add the CyberArk tools tap to Homebrew
brew tap cyberark/tools
brew update

# Install the Conjur CLI
brew install conjur-cli

What does this install?

The cyberark/tools Homebrew tap is a CyberArk-maintained repository of Homebrew formulas. The conjur-cli formula installs the Secrets Manager CLI v9.x, the Go-based CLI for managing CyberArk Secrets Manager resources.

  • Verify the installation by running:
conjur --version

You should see a version number starting with 9 printed in your terminal.

Install failed?

If brew install conjur-cli fails, make sure brew tap cyberark/tools ran successfully first. You can also download the CLI binary directly from the CyberArk Marketplace for macOS.

help me install the CyberArk Conjur CLI on macOS

Now connect the CLI to your CyberArk Secrets Manager SaaS tenant.

  • Initialize the CLI with your tenant URL by running:
conjur init saas -u https://[[CONJUR_SUBDOMAIN="your-tenant-subdomain"]].secretsmgr.cyberark.cloud/api

Where do I find my tenant subdomain?

Your tenant subdomain is the first part of your CyberArk Secrets Manager SaaS URL. For example, if your tenant URL is https://mycompany.secretsmgr.cyberark.cloud, the subdomain is mycompany.

This command creates a .conjurrc configuration file in your home directory with the connection details for your tenant.

  • Log in to your tenant by running:
conjur login

What prompts will I see?

The CLI prompts you for your CyberArk Identity username and password. If your tenant uses multi-factor authentication (MFA), you will also be asked to choose an MFA delivery method and enter the one-time code.

After successful authentication, the CLI stores your access token in the operating system's credential store.

  • Confirm you are connected by running:
conjur whoami

You should see output that includes your account name, username, and client IP address. This confirms the CLI can communicate with your Conjur Cloud tenant.

Login failing?

Double check that the URL you passed to conjur init ends with /api. The full format is https://<subdomain>.secretsmgr.cyberark.cloud/api.

If you entered the wrong URL, re-run the conjur init command with the --force flag to overwrite the existing configuration.

help me troubleshoot Conjur CLI login to my CyberArk Secrets Manager SaaS tenant

Your environment is ready. Next up, you will configure the JWT authenticator so your Kubernetes workloads can prove their identity to Conjur Cloud.

Configure the JWT Authenticator in Conjur Cloud

This step is conditional

If you already have a JWT authenticator endpoint configured and enabled for your Kubernetes cluster (e.g., authn-jwt/dev-cluster), skip ahead to Step 3.

Your local environment is ready. Now it is time to set up the trust relationship between your Minikube cluster and Conjur Cloud.

Kubernetes workloads authenticate to Conjur Cloud using service account tokens, which are JWTs. For Conjur Cloud to verify these tokens, it needs a JWT authenticator configured with your cluster's signing keys and issuer. Without this, none of your workloads can prove their identity to retrieve secrets.

In this step, get ready to:
  • Collect your Minikube cluster's OIDC issuer and JWKS signing keys.
  • Create and configure a JWT authenticator in Conjur Cloud.
  • Verify the authenticator is enabled and ready to accept requests.
Collect Kubernetes cluster information

Conjur Cloud needs two pieces of information from your cluster to verify service account tokens: the OIDC issuer URL and the JWKS (JSON Web Key Set) containing the public signing keys.

  • Retrieve your Minikube cluster's OIDC issuer URL by running this command:
kubectl get --raw /.well-known/openid-configuration | jq .issuer

You should see a URL printed in your terminal, such as https://kubernetes.default.svc.cluster.local. Copy this value and save it somewhere. You will need it shortly.

Seeing a jq error or empty output?

If you see command not found: jq, you need to install jq first. Run brew install jq and try the command again.

If you see an error about the cluster not being reachable, make sure Minikube is running with minikube status.

Help me troubleshoot my kubectl OIDC discovery command

  • Save your cluster's JWKS (the public signing keys) to a local file by running this command:
kubectl get --raw /openid/v1/jwks > jwks.json
  • Confirm the file was created by running:
ls jwks.json

You should see jwks.json listed in the output.

What is the JWKS file?

The JWKS file contains your cluster's public keys. When a workload sends a service account token to Conjur Cloud, Conjur uses these keys to verify the token's signature is genuine.

Since Minikube runs locally and its OIDC discovery endpoint is not accessible from the internet, you provide the JWKS as a static file instead of a URL.

Create and configure the JWT authenticator

With the issuer and JWKS in hand, you can now create the JWT authenticator in your Conjur Cloud tenant. You will use the Conjur Cloud UI for this.

  • Log in to your CyberArk Secrets Manager SaaS tenant in your browser.
  • Navigate to the Authenticators page in the left sidebar.
  • Click Create authenticator.
  • Select the workload type. Choose the Kubernetes option if available, or select Other. Click Next.
  • Enter a unique name for the authenticator, such as dev-cluster. This becomes the service ID (e.g., authn-jwt/dev-cluster). Click Next.

Now fill in the JWT encryption and verification fields.

  • Select Public keys (not JWKS URL, because Minikube's endpoint is not publicly accessible from the internet).
  • In the Public keys field, paste the contents of your jwks.json file. You can view the contents by running cat jwks.json in your terminal.
  • In the Issuer field, paste the issuer URL you retrieved in the previous substep.

Next, fill in the JWT claims mapping fields.

  • In the Token app property field, enter sub.
  • In the Identity path field, enter data/k8s-apps.
  • In the Audience field, enter conjur.
  • On the Summary page, review the authenticator's properties. Click Finish to create the authenticator.

What do these settings mean?

The token-app-property set to sub tells Conjur Cloud to identify workloads by the sub claim in the JWT. For Kubernetes service accounts, this claim follows the format system:serviceaccount:<namespace>:<service-account>.

The identity-path set to data/k8s-apps tells Conjur where to find the host policies for your workloads. The audience ensures only tokens intended for Conjur are accepted.

Why Public keys instead of JWKS URL?

Conjur Cloud runs on the internet and needs to reach the JWKS endpoint to fetch signing keys. Minikube runs locally, so its OIDC discovery endpoint is not accessible from outside your machine.

Providing the JWKS as a static public key set solves this. For production clusters with publicly reachable OIDC endpoints, you would use the JWKS URL option instead.

Verify the authenticator is enabled

Creating the authenticator does not always enable it automatically. Let's confirm it is active and ready to accept authentication requests.

  • Back in the Conjur Cloud UI, navigate to the Authenticators page.
  • Find your newly created JWT authenticator in the list. If it is not already enabled, click the authenticator's more actions icon and select Enable.

You can also verify from the command line.

  • List enabled authenticators by running this command:
conjur authenticator list

You should see your JWT authenticator listed (e.g., authn-jwt/dev-cluster) with an enabled status.

Don't see your authenticator in the list?

Make sure you clicked Finish on the Summary page in the UI. If the authenticator exists but is not enabled, enable it from the UI or run:

conjur authenticator enable --id authn-jwt/dev-cluster

Replace dev-cluster with the name you chose when creating the authenticator.

Also confirm your Conjur CLI session is still active by running conjur whoami. If the session expired, log in again with conjur login.

Help me troubleshoot my JWT authenticator setup

Note your service ID

Write down the full authenticator service ID you chose (e.g., authn-jwt/dev-cluster). You will reference this service ID in the Conjur Cloud policies and Helm chart values throughout the rest of this project.

Your Minikube cluster can now authenticate to Conjur Cloud using JWT tokens. Next up, you will prepare the Kubernetes cluster with the Golden ConfigMap and set up your application namespace.

Prepare the Kubernetes Cluster and Application Namespace

Your Minikube cluster is running and your JWT authenticator is configured in Conjur Cloud.

Before the Secrets Provider can sync secrets into your cluster, it needs to know where Conjur Cloud lives and how to authenticate. In this step, you will install two CyberArk Helm charts that lay this foundation.

In this step, get ready to:
  • Install the cluster preparation Helm chart to create the Golden ConfigMap with your Conjur Cloud connection details.
  • Install the namespace preparation Helm chart and create a service account for your application namespace.
Install the cluster preparation Helm chart

The Golden ConfigMap is a centralized Kubernetes ConfigMap that stores your Conjur Cloud connection details. Every workload setup method in the cluster reads from this single ConfigMap.

The Helm chart needs your Conjur Cloud CA certificate to establish a trusted TLS connection. You will retrieve this certificate first, then run the Helm install.

  • Retrieve your Conjur Cloud endpoint CA certificate and save it to conjur.pem by running this command:
openssl s_client -connect [[CONJUR_SUBDOMAIN="your-subdomain"]].secretsmgr.cyberark.cloud:443 \
  -showcerts </dev/null 2> /dev/null | \
  awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/ {print $0}' \
  > "conjur.pem"

What does this command do?

The openssl s_client command connects to your Conjur Cloud endpoint over TLS and prints the server's certificate chain.

The awk filter extracts just the PEM-encoded certificate block and writes it to conjur.pem. The Helm chart will base64-encode this file and embed it in the Golden ConfigMap.

  • Confirm the certificate was saved by running:
cat conjur.pem

You should see a block starting with -----BEGIN CERTIFICATE----- and ending with -----END CERTIFICATE-----.

Empty or missing certificate?

Check that your Conjur Cloud subdomain is correct. The URL format should be <subdomain>.secretsmgr.cyberark.cloud.

Make sure you have internet connectivity from your terminal. The openssl command needs to reach port 443 on the Conjur Cloud endpoint.

Help me troubleshoot my Conjur Cloud certificate retrieval

Now you have the certificate. Time to install the cluster preparation Helm chart.

  • Create the Golden ConfigMap conjur-configmap in the cyberark-conjur-jwt namespace by running this command:
helm install "cluster-prep" cyberark/conjur-config-cluster-prep \
  -n "cyberark-conjur-jwt" \
  --create-namespace \
  --set conjur.account="conjur" \
  --set conjur.applianceUrl="https://[[CONJUR_SUBDOMAIN="your-subdomain"]].secretsmgr.cyberark.cloud/api" \
  --set conjur.certificateBase64=$(cat conjur.pem | base64) \
  --set authnK8s.authenticatorID="[[AUTHN_JWT_SERVICE_ID="your-jwt-authenticator-service-id e.g. dev-cluster"]]" \
  --set authnK8s.clusterRole.create=false \
  --set authnK8s.serviceAccount.create=false

What does this command do?

  • conjur.account="conjur" sets the Conjur account. For Conjur Cloud SaaS, the account is always conjur.
  • conjur.applianceUrl is your Conjur Cloud API endpoint URL.
  • conjur.certificateBase64 base64-encodes the CA certificate on the fly. On macOS, base64 does not wrap output by default, so no -w 0 flag is needed.
  • authnK8s.authenticatorID is the JWT authenticator endpoint name you configured in Step 2 (for example, dev-cluster).
  • The clusterRole.create=false and serviceAccount.create=false flags skip creating a ClusterRole and ServiceAccount because JWT authentication does not need them.
  • Verify the Golden ConfigMap was created by running:
kubectl get configmap conjur-configmap -n cyberark-conjur-jwt

You should see a ConfigMap named conjur-configmap listed in the output.

Helm install failed?

If you see a certificate-related error, check that conjur.pem exists in your current directory and contains a valid PEM certificate block.

If you see an "already exists" error, remove the existing release first with helm uninstall cluster-prep -n cyberark-conjur-jwt and try again.

Help me troubleshoot the cluster-prep Helm chart installation

What is the Golden ConfigMap?

The Golden ConfigMap is a cluster-wide source of truth for Conjur Cloud connection details. It lives in the cyberark-conjur-jwt namespace and contains your tenant URL, CA certificate, and authenticator ID.

Each application namespace gets its own ConfigMap that references this Golden ConfigMap. This keeps the connection details centralized so you only update one place if your tenant details change.

Install the namespace preparation Helm chart and create a service account

The Golden ConfigMap is cluster-wide, but your application runs in its own namespace. The namespace preparation chart creates a local conjur-connect ConfigMap that references the Golden ConfigMap.

  • Prepare the test-app-namespace namespace with the conjur-connect ConfigMap by running this command:
helm install namespace-prep cyberark/conjur-config-namespace-prep \
  --create-namespace \
  --namespace test-app-namespace \
  --set conjurConfigMap.authnMethod="authn-jwt" \
  --set authnK8s.goldenConfigMap="conjur-configmap" \
  --set authnK8s.namespace="cyberark-conjur-jwt" \
  --set authnRoleBinding.create="false"

What does this command do?

  • conjurConfigMap.authnMethod="authn-jwt" tells the chart you are using JWT-based authentication instead of certificate-based.
  • authnK8s.goldenConfigMap="conjur-configmap" points to the Golden ConfigMap you just created.
  • authnK8s.namespace="cyberark-conjur-jwt" tells the chart which namespace holds the Golden ConfigMap.
  • authnRoleBinding.create="false" skips creating a RoleBinding because JWT authentication does not require one.
  • Verify the conjur-connect ConfigMap was created by running:
kubectl get configmap conjur-connect -n test-app-namespace

You should see a ConfigMap named conjur-connect listed in the test-app-namespace namespace.

Namespace prep Helm install failed?

If you see a "not found" error referencing the Golden ConfigMap, make sure the cluster-prep install from the previous substep completed successfully. Run kubectl get configmap conjur-configmap -n cyberark-conjur-jwt to confirm.

Help me troubleshoot the namespace preparation Helm chart

The namespace is prepared. Now you need a Kubernetes service account that your application workload will use to authenticate.

  • Create the test-app-sa service account in test-app-namespace by running this command:
kubectl create serviceaccount test-app-sa -n test-app-namespace
  • Verify the service account was created by running:
kubectl get serviceaccount test-app-sa -n test-app-namespace

You should see test-app-sa listed in the output.

Service account already exists?

If you see an "already exists" error, that is fine. The service account was created by a previous run. You can safely move on.

Help me troubleshoot creating the test-app-sa service account

Why does the workload need its own service account?

Kubernetes projects a JWT for each service account. The JWT authenticator in Conjur Cloud uses this token to verify the workload's identity. The token's sub claim contains the service account name and namespace, which Conjur matches against the host policy you will create in the next step.

Your cluster foundation is in place. The Golden ConfigMap holds your Conjur Cloud connection details. The application namespace has its own conjur-connect ConfigMap and a dedicated service account. Next up, you will define your workload identity and secrets in Conjur Cloud policy.

Load Conjur Cloud Policy and Set Secrets

Your Kubernetes cluster is prepped with the Golden ConfigMap and a ready application namespace. Now it is time to tell Conjur Cloud who this workload is and what secrets it is allowed to access.

Without policy, Conjur Cloud has no idea that your test-app-sa service account exists. You need to define a host identity for the workload, create the secrets it will consume, and grant the permissions that tie everything together.

In this step, get ready to:
  • Define a workload host identity and grant it access to the JWT authenticator.
  • Create secrets in Conjur Cloud and set their initial values.
  • Grant the workload host read and execute permissions on those secrets.
Create and load the workload host policy

A host in Conjur Cloud represents a non-human identity. Your Kubernetes workload authenticates as a host using its service account token. The host policy also carries JWT annotations that tell Conjur which namespace and service account to trust.

  • Create a file called test-app.yaml in the same folder where you saved conjur.pem, and paste the following content:
# Define the workload host identity for the test-app service account
- !policy
  id: k8s-apps
  body:
    - !group

    - &hosts
      - !host
        id: system:serviceaccount:test-app-namespace:test-app-sa
        annotations:
          authn-jwt/[[JWT_SERVICE_ID="your JWT authenticator service ID"]]/kubernetes.io/namespace: test-app-namespace
          authn-jwt/[[JWT_SERVICE_ID="your JWT authenticator service ID"]]/kubernetes.io/serviceaccount/name: test-app-sa

    - !grant
      role: !group
      members: *hosts

What does this policy do?

This policy creates a k8s-apps group, defines a host whose ID matches the Kubernetes service account token's sub claim, and grants that host membership in the group.

The annotations tell the JWT authenticator to verify the token's namespace and service account name. If either value does not match, authentication is denied.

  • Save test-app.yaml.
  • Load the host policy into Conjur Cloud under the data branch by running:
conjur policy load -f test-app.yaml -b data

You should see output listing the created resources, including the new host and group.

The host exists, but it cannot authenticate yet. You need a second policy that grants the k8s-apps group access to the JWT authenticator.

  • Create a file called grant-app-access.yaml and paste the following content:
# Grant the k8s-apps group membership in the authenticator's apps group
- !grant
  roles:
  - !group apps
  members:
  - !group /data/k8s-apps

What does this grant do?

Every JWT authenticator has an apps group that controls which hosts are allowed to authenticate through it. This policy adds your k8s-apps group as a member, so any host in that group can request a Conjur token via the JWT authenticator.

  • Save grant-app-access.yaml.
  • Load the grant policy into the JWT authenticator branch by running:
conjur policy load -f grant-app-access.yaml -b conjur/authn-jwt/[[JWT_SERVICE_ID="your JWT authenticator service ID"]]

You should see output confirming the grant was created successfully.

Seeing a 403 Forbidden or policy not found error?

  • Make sure the JWT authenticator service ID in the -b branch matches the one configured in your Conjur Cloud tenant exactly.
  • Confirm your Conjur CLI session is still active by running conjur whoami. If the session expired, run conjur login again.
  • Check that you loaded test-app.yaml into the data branch first. The grant policy references /data/k8s-apps, which must already exist.

Help me troubleshoot my Conjur policy load errors.

Create a secrets policy and set initial values

The host can authenticate, but there are no secrets for it to retrieve yet. You need to declare the secret variables in Conjur Cloud policy and then set their initial values.

  • Create a file called secrets.yaml and paste the following content:
# Declare the database credential variables
- !policy
  id: secrets
  body:
    - !variable db-username
    - !variable db-password

What does this policy do?

This creates two Conjur variables under the data/secrets path: db-username and db-password. Variables in Conjur Cloud are versioned, encrypted containers for sensitive values.

  • Save secrets.yaml.
  • Load the secrets policy into Conjur Cloud by running:
conjur policy load -f secrets.yaml -b data

You should see output listing the two new variables.

The variables exist but are empty. You need to set their initial values so the Secrets Provider has something to sync.

  • Set the initial secret values by running these commands:
conjur variable set -i data/secrets/db-username -v "app-user-v1"
conjur variable set -i data/secrets/db-password -v "S3cureP@ss-v1"
  • Verify the values were stored correctly by running:
conjur variable get -i data/secrets/db-username
conjur variable get -i data/secrets/db-password

You should see app-user-v1 and S3cureP@ss-v1 printed in the terminal output.

Seeing an empty response or variable not found?

  • Double check you loaded secrets.yaml into the data branch. If you loaded it into the wrong branch, the variable paths will not match.
  • Make sure the -i path in your conjur variable set command matches the full path data/secrets/db-username exactly.

Help me troubleshoot my Conjur variable set commands.

Grant the host access to the secrets

The host identity and the secrets both exist in Conjur Cloud, but they are not connected. Conjur follows a least-privilege model where every access relationship must be explicitly granted.

  • Create a file called grant-secrets-access.yaml and paste the following content:
# Grant the k8s-apps group read and execute on the database secrets
- !permit
  role: !group /data/k8s-apps
  privileges: [read, execute]
  resources:
    - !variable /data/secrets/db-username
    - !variable /data/secrets/db-password

What do read and execute mean here?

The read privilege allows the host to fetch the current value of a variable. The execute privilege allows the host to use the variable in an automated workflow. Both are required for the Secrets Provider to retrieve and inject secrets into Kubernetes.

  • Save grant-secrets-access.yaml.
  • Load the permissions policy into Conjur Cloud by running:
conjur policy load -f grant-secrets-access.yaml -b data

You should see output confirming the permit was created.

  • Verify the full policy chain is in place by listing the resources under the data branch:
conjur list --kind variable --search data/secrets

You should see both data/secrets/db-username and data/secrets/db-password listed in the output.

Policy loaded but variables not listed?

  • Verify that all three policy files were loaded into the data branch. The host policy, secrets policy, and permissions policy all share the same branch.
  • Check for typos in the variable names inside grant-secrets-access.yaml. The paths must match /data/secrets/db-username and /data/secrets/db-password exactly.

Help me troubleshoot my Conjur Cloud policy setup.

✔️ Awesome, I've got everything!

Great. Make sure you have saved all four policy files: test-app.yaml, grant-app-access.yaml, secrets.yaml, and grant-secrets-access.yaml.

ⓧ I'd like to double check the full code

Here are all four policy files for comparison.

- !policy
  id: k8s-apps
  body:
    - !group

    - &hosts
      - !host
        id: system:serviceaccount:test-app-namespace:test-app-sa
        annotations:
          authn-jwt/[[JWT_SERVICE_ID="your JWT authenticator service ID"]]/kubernetes.io/namespace: test-app-namespace
          authn-jwt/[[JWT_SERVICE_ID="your JWT authenticator service ID"]]/kubernetes.io/serviceaccount/name: test-app-sa

    - !grant
      role: !group
      members: *hosts
- !grant
  roles:
  - !group apps
  members:
  - !group /data/k8s-apps
- !policy
  id: secrets
  body:
    - !variable db-username
    - !variable db-password
- !permit
  role: !group /data/k8s-apps
  privileges: [read, execute]
  resources:
    - !variable /data/secrets/db-username
    - !variable /data/secrets/db-password

Your Conjur Cloud policy is fully wired. The workload host can authenticate, and it has permission to retrieve both secrets. Next up, you will deploy the Secrets Provider to sync these secrets into a native Kubernetes Secret and enable Reloader for automatic restarts.

Deploy the Secrets Provider with Reloader Enabled

Your Conjur Cloud policies are loaded and your secrets have their initial values. Now it's time to deploy the component that bridges Conjur Cloud and your Kubernetes cluster.

The CyberArk Secrets Provider runs as a Helm-managed Job in your namespace and syncs secrets into native Kubernetes Secrets. By enabling autoReload in the Helm chart, you also deploy Stakater Reloader as a subchart to automatically detect Secret changes.

In this step, get ready to:
  • Create a Kubernetes Secret with conjur-map mappings that tell the Secrets Provider which Conjur variables to sync.
  • Deploy the Secrets Provider Helm chart with Stakater Reloader enabled.
  • Verify the Secrets Provider Job completed and the db-credentials Secret contains your Conjur values.
Create the Kubernetes Secret with conjur-map

The Secrets Provider needs a mapping that tells it which Conjur variables to fetch and which Kubernetes Secret keys to populate. You define this mapping in a conjur-map field inside a Kubernetes Secret.

  • Create a file called db-credentials-secret.yaml and add the following manifest:
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: test-app-namespace
type: Opaque
stringData:
  conjur-map: |-
    username: data/secrets/db-username
    password: data/secrets/db-password

What does this manifest do?

The stringData.conjur-map field defines key-value pairs where each key becomes a data field in the Kubernetes Secret.

For example, username: data/secrets/db-username tells the Secrets Provider to fetch the Conjur variable at that path and store its value under the username key. After the Secrets Provider runs, the actual secret values replace the conjur-map content.

  • Save db-credentials-secret.yaml.
  • Apply the manifest to your cluster by running this command:
kubectl apply -f db-credentials-secret.yaml
  • Confirm the Secret was created by running:
kubectl get secret db-credentials -n test-app-namespace

You should see db-credentials listed with type Opaque.

Secret not created?

  • Check that the namespace field in your manifest says test-app-namespace. A typo here creates the Secret in the wrong namespace.
  • Make sure the YAML indentation uses spaces, not tabs. YAML does not accept tab characters.
  • Why isn't my Kubernetes Secret being created from my YAML manifest?

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: test-app-namespace
type: Opaque
stringData:
  conjur-map: |-
    username: data/secrets/db-username
    password: data/secrets/db-password
Deploy the Secrets Provider Helm chart with Reloader

The Secrets Provider Helm chart needs a values file that configures JWT authentication, the list of Kubernetes Secrets to populate, and whether to deploy Reloader. You will create this values file first, then install the chart.

  • Create a file called custom-values.yaml and add the following configuration:
# Tell the Secrets Provider which K8s Secrets to populate
environment:
  k8sSecrets: [db-credentials]
  conjur:
    conjurConnConfigMap: conjur-connect
    # JWT authentication settings for Kubernetes service account tokens
    authnJWT:
      projectToken: true
      projectedFilename: jwt
      audience: conjur
      expiration: 86400

# Deploy Stakater Reloader as a subchart
autoReload:
  enabled: true

What do these values configure?

  • k8sSecrets: [db-credentials] tells the Secrets Provider which Kubernetes Secrets to populate with values from Conjur Cloud.
  • projectToken: true mounts a projected service account token into the pod. The Secrets Provider uses this token to authenticate to Conjur Cloud via JWT.
  • audience: conjur sets the expected audience claim in the JWT token that Conjur Cloud validates.
  • autoReload.enabled: true deploys Stakater Reloader as a subchart alongside the Secrets Provider. This is the officially supported integration path from CyberArk.
  • Save custom-values.yaml.

✔️ Awesome, I've got everything!

Great. Make sure the file is saved before running the Helm install.

ⓧ I'd like to double check the full code

environment:
  k8sSecrets: [db-credentials]
  conjur:
    conjurConnConfigMap: conjur-connect
    authnJWT:
      projectToken: true
      projectedFilename: jwt
      audience: conjur
      expiration: 86400

autoReload:
  enabled: true
  • Deploy the Secrets Provider using the Helm chart by running this command:
helm install secrets-provider cyberark/secrets-provider -f custom-values.yaml --set environment.conjur.conjurConnConfigMap=conjur-connect -n test-app-namespace

What does this command do?

  • helm install secrets-provider creates a Helm release named secrets-provider.
  • -f custom-values.yaml applies your JWT auth and Reloader configuration.
  • --set environment.conjur.conjurConnConfigMap=conjur-connect points the Secrets Provider to the conjur-connect ConfigMap created during namespace preparation.
  • The chart creates a Job that authenticates to Conjur Cloud via JWT and populates the db-credentials Secret with actual values.
  • Check the Helm release status by running:
helm list -n test-app-namespace

You should see secrets-provider listed with status deployed.

Helm install failed?

  • If you see a cannot re-use a name that is still in use error, a previous release with the same name exists. Run helm uninstall secrets-provider -n test-app-namespace and try again.
  • If you see RBAC or permission errors, confirm the test-app-sa service account exists in test-app-namespace and that the conjur-connect ConfigMap is present.
  • Check for YAML syntax errors in custom-values.yaml. Even one incorrect indentation level can cause Helm to misinterpret the values.
  • Why is my Secrets Provider Helm install failing?
Verify the Secrets Provider Job completed and Reloader is running

The Helm chart created a Secrets Provider Job and a Reloader Deployment. You need to confirm both are healthy and that the db-credentials Secret now holds real values from Conjur Cloud.

  • Check that the Secrets Provider Job completed by running:
kubectl get jobs -n test-app-namespace

You should see a Job with 1/1 under the COMPLETIONS column.

  • Verify the Reloader pod is running:
kubectl get pods -n test-app-namespace -l app.kubernetes.io/name=reloader

You should see a Reloader pod with status Running.

  • Confirm the db-credentials Secret now contains actual values from Conjur Cloud by running:
kubectl get secret db-credentials -n test-app-namespace -o jsonpath='{.data.username}' | base64 -d

You should see app-user-v1 printed to the terminal. This confirms the Secrets Provider authenticated to Conjur Cloud, fetched the secret, and wrote it into the Kubernetes Secret.

Secret value not showing up?

  • If the decoded value still shows the conjur-map content instead of app-user-v1, the Secrets Provider Job did not populate the Secret. Check the Job logs by running kubectl logs job/<job-name> -n test-app-namespace.
  • If the logs show an authentication error, verify the JWT authenticator service ID matches what you configured in the Golden ConfigMap. Also confirm the host identity in your Conjur policy matches system:serviceaccount:test-app-namespace:test-app-sa exactly.
  • If the Job shows 0/1 completions, the container may have failed to start. Check for image pull errors or CrashLoopBackOff status with kubectl describe job/<job-name> -n test-app-namespace.
  • Why is my Secrets Provider Job not populating the Kubernetes Secret with values from Conjur Cloud?

Why does the Secrets Provider run as a Job?

The Secrets Provider runs in Application mode by default. It authenticates, syncs secrets, and exits. To pick up rotated secrets later, you re-trigger the Job.

You will do exactly this in a later step when you demonstrate live secret rotation.

Your Secrets Provider is syncing secrets and Reloader is watching for changes. Next up, you'll deploy a sample application and annotate it so Reloader triggers automatic restarts whenever a secret changes.

Deploy the Sample Application and Annotate for Restart

Your Secrets Provider is syncing secrets from Conjur Cloud into Kubernetes, and Stakater Reloader is standing by to detect changes. The missing piece is an application that actually consumes those secrets.

In this step, you'll deploy a simple nginx-based application that reads the db-credentials Kubernetes Secret as environment variables. You'll also annotate the Deployment so Reloader knows to trigger a rolling restart when those secrets change.

In this step, get ready to:
  • Deploy a sample application that reads secrets from the db-credentials Kubernetes Secret.
  • Annotate the Deployment so Reloader triggers automatic restarts.
  • Verify the application pod has the correct secret values from Conjur Cloud.
Deploy a sample application

The application needs to consume the secrets that the Secrets Provider synced into the db-credentials Kubernetes Secret. The simplest way to do this is by mounting individual keys from the Secret as environment variables using secretKeyRef.

  • Create a file called test-app-deployment.yaml in your working folder and paste the following manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
  namespace: test-app-namespace
  labels:
    app: test-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      # Use the service account that Conjur recognizes via JWT
      serviceAccountName: test-app-sa
      containers:
        - name: test-app
          image: nginx:alpine
          ports:
            - containerPort: 80
          env:
            # Map Kubernetes Secret keys to environment variables
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password

What does this manifest do?

This Deployment creates a single nginx pod that acts as your test application.

  • serviceAccountName: test-app-sa tells Kubernetes to use the service account you created earlier. This is the identity that the JWT authenticator recognizes.
  • env.valueFrom.secretKeyRef reads individual keys from the db-credentials Secret and injects them as DB_USERNAME and DB_PASSWORD environment variables inside the container.
  • This direct reference to the Secret is also what allows Reloader to detect the dependency between this Deployment and the db-credentials Secret.
  • Apply the manifest by running this command:
kubectl apply -f test-app-deployment.yaml
  • Watch the rollout complete by running:
kubectl rollout status deployment/test-app -n test-app-namespace

You should see deployment "test-app" successfully rolled out in your terminal output.

Rollout stuck or failing?

  • Check the pod status with kubectl get pods -n test-app-namespace. If the pod is in ImagePullBackOff, make sure your Minikube cluster has internet access to pull the nginx:alpine image.
  • Confirm the test-app-sa service account exists in test-app-namespace. If it's missing, the pod will fail to schedule.
  • Run kubectl describe pod -l app=test-app -n test-app-namespace and check the Events section for specific error messages.

Why is my test-app Deployment stuck or failing to start?

Annotate the Deployment for automatic restart

Reloader watches for changes to Kubernetes Secrets, but it only restarts Deployments that explicitly opt in. The conjur.org/automatic-restart annotation is that opt-in signal.

  • Add the automatic restart annotation to the test-app Deployment by running:
kubectl annotate deployment test-app conjur.org/automatic-restart="true" -n test-app-namespace

What does this annotation do?

Setting conjur.org/automatic-restart: "true" tells Reloader to trigger a rolling restart of this Deployment whenever any Kubernetes Secret it references changes. Since your Deployment reads from db-credentials via secretKeyRef, Reloader detects that dependency automatically.

CyberArk uses its own annotation names (conjur.org/automatic-restart, conjur.org/restart-secrets) instead of the default Stakater annotations. The CyberArk Helm chart maps these to Reloader behavior behind the scenes.

  • Verify the annotation was applied by running:
kubectl get deployment test-app -n test-app-namespace -o yaml | grep -E 'conjur\.org/(automatic-restart|restart-secrets)'

You should see conjur.org/automatic-restart: "true" in the output.

Update your YAML file too

The kubectl annotate command only updates the live object in the cluster. For a production workflow, add the annotation directly into your test-app-deployment.yaml file under metadata.annotations so it persists across re-applies.

Annotation not showing up?

  • Make sure you included the -n test-app-namespace flag. Without it, kubectl targets the default namespace.
  • Check that the Deployment name is exactly test-app by running kubectl get deployments -n test-app-namespace.

Why isn't my annotation appearing on the test-app Deployment?

✔️ Awesome, I've got everything!

Great. Make sure you've saved test-app-deployment.yaml and that the annotation is showing on the live Deployment.

ⓧ I'd like to double check the full code

Here is the recommended final state of test-app-deployment.yaml with the annotation included directly in the file. Update your local copy to match this so it persists across re-applies.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
  namespace: test-app-namespace
  labels:
    app: test-app
  annotations:
    conjur.org/automatic-restart: "true"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      serviceAccountName: test-app-sa
      containers:
        - name: test-app
          image: nginx:alpine
          ports:
            - containerPort: 80
          env:
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password
Verify the application has the correct secret values

The secrets have traveled from Conjur Cloud, through the Secrets Provider, into the db-credentials Kubernetes Secret, and finally into your pod as environment variables. Time to confirm they arrived correctly.

  • Exec into the running pod and check the environment variables by running:
kubectl exec -it deployment/test-app -n test-app-namespace -- env | grep DB_

What should I see?

You should see these two lines in the output:

  • DB_USERNAME=app-user-v1
  • DB_PASSWORD=S3cureP@ss-v1

These are the exact values you set in Conjur Cloud back in Step 4. If they match, the entire injection pipeline is working end to end.

Not seeing the expected values?

  • If the variables are empty or missing, check that the db-credentials Secret was populated by the Secrets Provider. Run kubectl get secret db-credentials -n test-app-namespace -o jsonpath='{.data.username}' | base64 -d to verify the Secret contents directly.
  • Make sure the key names in your manifest (username and password) match the keys in the db-credentials Secret exactly. Key names are case-sensitive.
  • If you redeployed the pod after the Secrets Provider Job completed, the Secret values should already be present. If the Job hasn't run, the Secret may still contain only the conjur-map data and not the actual values.

Help me debug why my test-app pod doesn't have the correct DB_USERNAME and DB_PASSWORD values.

Your application is live, consuming secrets from Conjur Cloud, and Reloader is watching for changes. Next up, you'll rotate a secret in Conjur Cloud and watch the entire pipeline react in real time.

Demonstrate Live Secret Rotation

Your sample application is deployed, annotated for automatic restart, and running with the initial secret values from Conjur Cloud. Now comes the moment of truth.

In this step, you will change a secret directly in Conjur Cloud and watch the entire rotation pipeline in action. The Secrets Provider syncs the updated value into Kubernetes, and Reloader triggers a rolling restart so your application picks up the new credentials automatically.

In this step, get ready to:
  • Update a secret value in Conjur Cloud.
  • Retrigger the Secrets Provider to sync the change into Kubernetes.
  • Verify the application pods restarted with the new secret value.
Update a secret in Conjur Cloud

The Conjur CLI lets you overwrite any variable value with a single command. The existing Secrets Provider and Reloader setup handles everything downstream.

  • Update the db-password variable to a new value by running this command:
conjur variable set -i data/secrets/db-password -v "N3wS3cure-v2!"

What does this command do?

  • conjur variable set overwrites the current value of data/secrets/db-password in your Conjur Cloud tenant.
  • The old value S3cureP@ss-v1 is replaced with N3wS3cure-v2!.
  • Nothing changes in Kubernetes yet. The Secrets Provider needs to run again to detect and sync this update.

Seeing a permission error?

  • Confirm your Conjur CLI session is still active by running conjur whoami. If it returns an error, log in again with conjur login.
  • Check that the variable path data/secrets/db-password matches what you loaded in your secrets.yaml policy.

Why is my conjur variable set command failing?

Retrigger the Secrets Provider and observe Reloader

The Secrets Provider in this project runs in Application mode. This means it executes as a one-shot Kubernetes Job that fetches secrets and exits.

To pick up the changed secret, you need to retrigger the Job. You do this by deleting the completed Job and running a Helm upgrade.

Why manually retrigger?

In Application mode, the Secrets Provider runs once and exits. For production environments, CyberArk recommends Standalone mode, where the Secrets Provider runs as a persistent Deployment with periodic refresh.

This project uses Application mode to keep the setup simple. You retrigger manually with a Helm upgrade to demonstrate the rotation flow.

  • Delete the completed Secrets Provider Job and retrigger it by running these commands:
# Delete the completed Job so Helm can recreate it
kubectl delete job -l app=secrets-provider -n test-app-namespace

# Retrigger the Secrets Provider via Helm upgrade
helm upgrade secrets-provider cyberark/secrets-provider -f custom-values.yaml --set environment.conjur.conjurConnConfigMap=conjur-connect -n test-app-namespace

What do these commands do?

  • kubectl delete job removes the completed Job so Helm can recreate it. Kubernetes does not allow rerunning a completed Job in place.
  • helm upgrade reruns the Secrets Provider release, creating a fresh Job that authenticates to Conjur Cloud, fetches the latest secret values, and updates the db-credentials Kubernetes Secret.
  • Once the Secret is updated, Reloader detects the change and triggers a rolling restart on the test-app Deployment.
  • Check for Reloader events by running this command:
kubectl get events -n test-app-namespace --field-selector reason=Reloaded

You should see an event showing that Reloader detected a change in the db-credentials Secret and triggered a rolling update on the test-app Deployment.

  • Confirm the rolling restart completed by running:
kubectl rollout status deployment/test-app -n test-app-namespace

You should see deployment "test-app" successfully rolled out once the new pod is ready.

No Reloaded event showing up?

  • Confirm the Secrets Provider Job completed successfully by running kubectl get jobs -n test-app-namespace. The new Job should show 1/1 completions.
  • Check that Reloader is still running by running kubectl get pods -n test-app-namespace -l app.kubernetes.io/name=reloader. You should see a pod in Running status.
  • Verify the test-app Deployment still has the restart annotation by running kubectl get deployment test-app -n test-app-namespace -o yaml | grep -E 'conjur\.org/(automatic-restart|restart-secrets)'.

Why isn't Reloader triggering a rolling restart after the Secrets Provider synced?

Verify the application now has the updated secret

The rolling restart replaced your old pod with a new one. The final check confirms the new pod loaded the rotated secret value as an environment variable.

  • Exec into the running pod and check the environment variables by running:
kubectl exec -it deployment/test-app -n test-app-namespace -- env | grep DB_

You should see DB_USERNAME=app-user-v1 and DB_PASSWORD=N3wS3cure-v2!.

What does this confirm?

This single output proves the complete end-to-end rotation pipeline is working.

  • The secret was updated in Conjur Cloud.
  • The Secrets Provider synced the new value into the Kubernetes Secret.
  • Reloader detected the Secret change and triggered a rolling restart.
  • The new pod loaded the fresh credentials as environment variables. No manual intervention required on the Kubernetes side.

Still seeing the old password?

  • Check the raw Kubernetes Secret value by running kubectl get secret db-credentials -n test-app-namespace -o jsonpath='{.data.password}' | base64 -d. If this still shows S3cureP@ss-v1, the Secrets Provider Job did not sync successfully.
  • Make sure you are exec-ing into the newly created pod, not a cached session from the old pod. Run kubectl get pods -n test-app-namespace and confirm the pod age is recent.

My pod is still showing old secret values after the rotation flow. How do I debug this?

You have a fully operational secrets rotation pipeline. Change a value in Conjur Cloud, retrigger the sync, and your application pods automatically restart with the new credentials.

Up next in the Secret Mission, you can take this further with targeted restart annotations, health monitoring via liveness probes, and high availability for Reloader.

Secret mission

Targeted Restart and Health Monitoring

Your rotation pipeline works, but it restarts pods for every secret change. What if you only wanted to restart for specific secrets? In this mission, you will configure targeted restart annotations, set up a sentinel file liveness probe for stale-secret detection, and enable Reloader high availability for production readiness.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs on a local Minikube cluster, so there are no ongoing cloud costs. Your CyberArk Secrets Manager SaaS tenant is a pre-existing resource and is not affected by cleanup here.

Resources you used:

  • Minikube cluster (local Kubernetes environment).
  • Helm releases: cluster-prep, namespace-prep, secrets-provider.
  • Kubernetes namespaces: cyberark-conjur-jwt and test-app-namespace.
  • Kubernetes resources: test-app Deployment, db-credentials Secret, test-app-sa service account.
  • Conjur Cloud policies and secrets loaded into your tenant.
  • Local files: test-app.yaml, grant-app-access.yaml, secrets.yaml, grant-secrets-access.yaml, db-credentials-secret.yaml, custom-values.yaml, test-app-deployment.yaml, conjur.pem, jwks.json.

Keep everything running

No action needed. Choose this if you are still actively building or plan to experiment further with the secrets rotation pipeline.

  • Your Minikube cluster stays running and all Helm releases remain deployed.
  • Conjur Cloud policies and secrets remain in your tenant.
  • Local YAML files stay on disk for easy reference.

Pause - I'll come back to this later

Shut down the Minikube cluster to free up memory and CPU. Your cluster state is preserved so you can resume later.

  • Stop Minikube by running:
minikube stop
  • When you are ready to resume, start Minikube again by running:
minikube start --driver=docker
  • All Helm releases, namespaces, and Kubernetes resources are preserved when Minikube restarts.
  • Conjur Cloud policies and secrets remain in your tenant. No action needed there.
  • Keep your local YAML files on disk so you can reference them later.

Delete - I don't want to use this again

Remove all project resources from your local machine and clean up the Conjur Cloud policies.

  • Uninstall the Helm releases by running these commands:
helm uninstall secrets-provider -n test-app-namespace
helm uninstall namespace-prep -n test-app-namespace
helm uninstall cluster-prep -n cyberark-conjur-jwt
  • Delete the Kubernetes namespaces by running:
kubectl delete namespace test-app-namespace
kubectl delete namespace cyberark-conjur-jwt
  • Delete the Minikube cluster entirely by running:
minikube delete
  • Remove the CyberArk Helm charts repository by running:
helm repo remove cyberark
  • Delete the local YAML and certificate files you created during this project.
  • Optionally, remove the Conjur Cloud policies and secrets from your tenant using the Conjur Cloud UI or CLI. The policies loaded under data/k8s-apps and data/secrets can be deleted if you no longer need them.

Mission accomplished

That's a Wrap!

Nice work! You just built a complete secrets injection and auto-rotation pipeline using CyberArk Secrets Provider and Stakater Reloader on a local Minikube cluster.

You can now change a secret in Conjur Cloud and watch it automatically propagate to Kubernetes, triggering a rolling restart with zero manual intervention.

You've learned how to:

  • Configure JWT-based authentication with a Golden ConfigMap and load Conjur Cloud policy defining workload identity, secrets, and access grants.
  • Deploy the CyberArk Secrets Provider via Helm to sync Conjur Cloud secrets into native Kubernetes Secrets.
  • Enable Stakater Reloader and demonstrate a live end-to-end secret rotation, watching a changed secret propagate from Conjur Cloud to Kubernetes and trigger an automatic pod restart.
  • Secret Mission: Configure targeted restart annotations, sentinel file liveness probes, and Reloader high availability for production readiness.

Ready to quiz yourself?