Install External Secrets Operator on Kubernetes with Helm

External Secrets Operator is a Kubernetes operator that can be used to connect your cluster with your external secret management systems. This operator supports a variety of secret management systems, including AWS Secrets Manager, HashiCorp Vault, Google Secrets Manager, Azure Key Vault, IBM Cloud Secrets Manager, CyberArk Secrets Manager, Pulumi ESC, and many others. The operator does this by connecting with the external secret management systems through the API and injecting the data directly into a Kubernetes Secret within your cluster.

Installing External Secrets Operator with Helm

External secrets operator runs as a deployment within your Kubernetes environment. It makes use of CustomResourceDefinitions to set up and connect to secret providers through SecretStore resources, and it manages Kubernetes secret resources through the use of ExternalSecret resources.

When installing with Helm, the default option is to install and manage the CRDs as part of your helm release. If you don’t wish to have the CRDs automatically upgraded and managed, you must set the installCRDs option to false.

Install the CRDs outsude of Helm using the following command:

kubectl apply -f "https://raw.githubusercontent.com/external-secrets/external-secrets/refs/heads/main/deploy/crds/bundle.yaml" --server-side

Sample Output:

customresourcedefinition.apiextensions.k8s.io/clusterexternalsecrets.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/clusterpushsecrets.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/clustersecretstores.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/externalsecrets.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/pushsecrets.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/secretstores.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/acraccesstokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/cloudsmithaccesstokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/clustergenerators.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/ecrauthorizationtokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/fakes.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/gcraccesstokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/generatorstates.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/githubaccesstokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/grafanas.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/mfas.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/passwords.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/quayaccesstokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/sshkeys.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/stssessiontokens.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/uuids.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/vaultdynamicsecrets.generators.external-secrets.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/webhooks.generators.external-secrets.io serverside-applied

Confirm that the CRDs are there:

kubectl get crds | grep external

Sample Output:

acraccesstokens.generators.external-secrets.io          2026-02-04T09:33:41Z
cloudsmithaccesstokens.generators.external-secrets.io   2026-02-04T09:33:41Z
clusterexternalsecrets.external-secrets.io              2026-02-04T09:33:39Z
clustergenerators.generators.external-secrets.io        2026-02-04T09:33:42Z
clusterpushsecrets.external-secrets.io                  2026-02-04T09:33:39Z
clustersecretstores.external-secrets.io                 2026-02-04T09:33:40Z
ecrauthorizationtokens.generators.external-secrets.io   2026-02-04T09:33:42Z
externalsecrets.external-secrets.io                     2026-02-04T09:33:40Z
fakes.generators.external-secrets.io                    2026-02-04T09:33:42Z
gcraccesstokens.generators.external-secrets.io          2026-02-04T09:33:42Z
generatorstates.generators.external-secrets.io          2026-02-04T09:33:42Z
githubaccesstokens.generators.external-secrets.io       2026-02-04T09:33:43Z
grafanas.generators.external-secrets.io                 2026-02-04T09:33:43Z
mfas.generators.external-secrets.io                     2026-02-04T09:33:43Z
passwords.generators.external-secrets.io                2026-02-04T09:33:43Z
pushsecrets.external-secrets.io                         2026-02-04T09:33:40Z
quayaccesstokens.generators.external-secrets.io         2026-02-04T09:33:43Z
secretstores.external-secrets.io                        2026-02-04T09:33:41Z
sshkeys.generators.external-secrets.io                  2026-02-04T09:33:43Z
stssessiontokens.generators.external-secrets.io         2026-02-04T09:33:43Z
uuids.generators.external-secrets.io                    2026-02-04T09:33:43Z
vaultdynamicsecrets.generators.external-secrets.io      2026-02-04T09:33:43Z
webhooks.generators.external-secrets.io                 2026-02-04T09:33:44Z

Install from Chart Repository

Then add the helm repository and install the operator as follows:

helm repo add external-secrets https://charts.external-secrets.io

helm install external-secrets \
   external-secrets/external-secrets \
    -n external-secrets \
    --create-namespace \
    --set installCRDs=false

Sample Output:

Then check that all the pods are running in the external-secrets namespace as follows:

$ kubectl get pods -n external-secrets
NAME                                               READY   STATUS    RESTARTS   AGE
external-secrets-7b8954bbc6-kmmcl                  1/1     Running   0          2m44s
external-secrets-cert-controller-96579c897-sl6ct   1/1     Running   0          2m44s
external-secrets-webhook-57d68f65f6-wdkzc          1/1     Running   0          2m44s

You can also check the api-resources associated with the operator:

$ kubectl api-resources | grep external
clusterexternalsecrets              ces                       external-secrets.io/v1                      false        ClusterExternalSecret
clusterpushsecrets                                            external-secrets.io/v1alpha1                false        ClusterPushSecret
clustersecretstores                 css                       external-secrets.io/v1                      false        ClusterSecretStore
externalsecrets                     es                        external-secrets.io/v1                      true         ExternalSecret
pushsecrets                         ps                        external-secrets.io/v1alpha1                true         PushSecret
secretstores                        ss                        external-secrets.io/v1                      true         SecretStore
acraccesstokens                                               generators.external-secrets.io/v1alpha1     true         ACRAccessToken
cloudsmithaccesstokens                                        generators.external-secrets.io/v1alpha1     true         CloudsmithAccessToken
clustergenerators                                             generators.external-secrets.io/v1alpha1     false        ClusterGenerator
ecrauthorizationtokens                                        generators.external-secrets.io/v1alpha1     true         ECRAuthorizationToken
fakes                                                         generators.external-secrets.io/v1alpha1     true         Fake
gcraccesstokens                                               generators.external-secrets.io/v1alpha1     true         GCRAccessToken
generatorstates                     gs                        generators.external-secrets.io/v1alpha1     true         GeneratorState
githubaccesstokens                                            generators.external-secrets.io/v1alpha1     true         GithubAccessToken
grafanas                                                      generators.external-secrets.io/v1alpha1     true         Grafana
mfas                                                          generators.external-secrets.io/v1alpha1     true         MFA
passwords                                                     generators.external-secrets.io/v1alpha1     true         Password
quayaccesstokens                                              generators.external-secrets.io/v1alpha1     true         QuayAccessToken
sshkeys                                                       generators.external-secrets.io/v1alpha1     true         SSHKey
stssessiontokens                                              generators.external-secrets.io/v1alpha1     true         STSSessionToken
uuids                                                         generators.external-secrets.io/v1alpha1     true         UUID
vaultdynamicsecrets                                           generators.external-secrets.io/v1alpha1     true         VaultDynamicSecret
webhooks                                                      generators.external-secrets.io/v1alpha1     true         Webhook

Using External Secrets Operator

For the purposes of the demo in this guide, let’s create a secret containing my AWS account credentials, and don’t worry, they are only dummy keys, and not valid.

Let’s create a secret as follows:

echo -n 'BJBVQ2X66EFT4YJXPMRO' > ./access-key-id
echo -n 'gmOrd8v-fnqN77rfNQtm55yuGKF6pRSw\GHTQ3aK' > ./secret-access-key
kubectl create secret generic awssm-secret --from-file=./access-key-id --from-file=./secret-access-key

Then define a secret store as follows:

sudo tee ./basic-secret-store.yaml > /dev/null <<'EOF'
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: secretstore-sample
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        secretRef:
          accessKeyIDSecretRef:
            name: awssm-secret
            key: access-key-id
          secretAccessKeySecretRef:
            name: awssm-secret
            key: secret-access-key
EOF

Apply the manifest to create the secret store:

kubectl apply -f basic-secret-store.yaml

Define an external secret as follows:

sudo tee ./basic-external-secret.yaml > /dev/null <<'EOF'
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: sample-external-secret
spec:
  refreshInterval: 1h0m0s
  secretStoreRef:
    name: secretstore-sample
    kind: SecretStore
  target:
    name: db-credentials
    creationPolicy: Owner

# For a single key in one secret
  data:
  - secretKey: password
    remoteRef:
      key: prod/db/password # name of the key in aws secrets manager

## For multiple keys in one secret, use dataFrom: instead of data:
  dataFrom:
  - extract:
      key: dev/db/credentials # name of the key in aws secrest manager
EOF

My secret in AWS Secrets Manager is as follows:

So I used the dataFrom: instead of data:.

Apply the manifest to create the key:

kubectl apply -f basic-external-secret.yaml

Check that the secret has been created:

$ kubectl get externalsecret
NAME                     STORETYPE     STORE                REFRESH INTERVAL   STATUS         READY
sample-external-secret   SecretStore   secretstore-sample   1h0m0s             SecretSynced   True

Describe the secret to see the full details:

kubectl describe externalsecret sample-external-secret

Sample Output:

Name:         sample-external-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  external-secrets.io/v1
Kind:         ExternalSecret
Metadata:
  Creation Timestamp:  2026-02-04T11:49:51Z
  Finalizers:
    externalsecrets.external-secrets.io/externalsecret-cleanup
  Generation:        1
  Resource Version:  9132864
  UID:               39833ddd-b5cf-47b8-84c1-28215fb549d7
Spec:
  Data From:
    Extract:
      Conversion Strategy:  Default
      Decoding Strategy:    None
      Key:                  dev/db/credentials
      Metadata Policy:      None
  Refresh Interval:         1h0m0s
  Secret Store Ref:
    Kind:  SecretStore
    Name:  secretstore-sample
  Target:
    Creation Policy:  Owner
    Deletion Policy:  Retain
    Name:             db-credentials
Status:
  Binding:
    Name:  db-credentials
  Conditions:
    Last Transition Time:   2026-02-04T11:49:52Z
    Message:                secret synced
    Reason:                 SecretSynced
    Status:                 True
    Type:                   Ready
  Refresh Time:             2026-02-04T11:49:51Z
  Synced Resource Version:  1-344b5e002febafa14fa2b8f8674005203bb27f953dd4aba043fb662c
Events:
  Type    Reason   Age    From              Message
  ----    ------   ----   ----              -------
  Normal  Created  2m27s  external-secrets  secret created

We get all the key-value pairs present over the remote secret store. These key-values can be passed in as environment variables as follows:

        env:
          - name: key1
            valueFrom:
              secretKeyRef:
                name: db-credentials
                key: username

          - name: key2
            valueFrom:
              secretKeyRef:
                name: db-credentials
                key: password

We can check that both values are stored in the secret by running the following commands:

kubectl get secret db-credentials -n <namespace> -o jsonpath='{.data.username}' | base64 -d
kubectl get secret db-credentials -n <namespace> -o jsonpath='{.data.surname}' | base64 -d

Sample Output:

There you have it, we hope that this guide was helpful to you. Thanks for sticking with us. Please out our other guides below:

Join our Linux and open source community. Subscribe to our newsletter for tips, tricks, and collaboration opportunities!

Recent Post

Unlock the Right Solutions with Confidence

At CloudSpinx, we don’t just offer services - we deliver clarity, direction, and results. Whether you're navigating cloud adoption, scaling infrastructure, or solving DevOps challenges, our seasoned experts help you make smart, strategic decisions with total confidence. Let us turn complexity into opportunity and bring your vision to life.

Leave a Comment

Your email address will not be published. Required fields are marked *

Related Post

GitLab has evolved to be a complete DevOps platform delivered as a single application. With GitLab you can comfortably do […]

In this blog post we’ll take you through a step-by-step installation of Apache Tomcat 10 on Amazon Linux 2023. Apache […]

InfluxDB is a popular open source time series database with APIs for querying and storing data and processing the data […]

Let's Connect

Unleash the full potential of your business with CloudSpinx. Our expert solutions specialists are standing by to answer your questions and tailor a plan that perfectly aligns with your unique needs.
You will get a response from our solutions specialist within 12 hours
We understand emergencies can be stressful. For immediate assistance, chat with us now

Contact CloudSpinx today!

Download CloudSpinx Profile

Discover the full spectrum of our expertise and services by downloading our detailed Company Profile. Simply enter your first name, last name, and email address.