Search:

Kubernetes secret management using the External Secrets Operator-EKS

A wonderful serenity has taken possession of my entire soul.

Kubernetes secret management using the External Secrets Operator-EKS

In this blog post, I am going to examine the External Secrets Operator and demonstrate how to store your secrets externally on the AWS Secrets Manager.

Kubernetes includes native capabilities for managing secrets in the form of Kubernetes Secrets to satisfy the requirement of safely delivering secrets to running applications. To improve security, administration, and the ability to track how secrets are used, centralized secret management can be carried out outside of Kubernetes clusters using an external secret store such as Hashicorp Vault, AWS Secrets Manager, etc. One way to store secrets outside the K8s cluster is with the help of the External Secrets Operator open-source project. 

What Is the Function of the External Secrets Operator?

The External Secrets Operator's objective is to synchronize secrets from external APIs with Kubernetes. The ESO manages secrets via Custom Resource Definitions. ExternalSecret, SecretStore, and ClusterSecretStore are user-friendly wrappers around the external API that store and manage secrets on your behalf.

Your secrets are managed by the "ExternalSecret" CRD and the controller uses ExternalSecret’s data to create secrets. When you use External Secrets to read secrets from an external secret store, the data is stored in the Kubernetes control plane as native Kubernetes Secrets. 

SecretStore and ExternalSecret CRDs are important to understand this demo and how ESO works.

SecretStore CRD is used for the authentication and access management of the external secret store.

ExternalSecret CRD is used for the specific secret that is going to be pulled. The controller uses ExternalSecret’s data to create secrets and sync them at a time interval you choose.

eso

 

Let's Practice a Little Bit

This tutorial will show you how to sync a secret from the AWS Secrets Manager to your EKS cluster using the External Secrets Operator.

To properly follow this tutorial, make sure you have installed the following tools:

 

pasted image 0-2

Creating an EKS Cluster

If you already have an EKS Cluster, you can skip this step. I am going to deploy my own EKS Cluster using eksctl, which is a simple CLI tool for creating and managing EKS Clusters.

The following commands will create my EKS Cluster.

 


eksctl create cluster -f cluster-config.yaml



The code example below provides an overview of the cluster-config.yaml file.


apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eso-test-cluster
  region: eu-central-1

nodeGroups:
  - name: ng-1
    instanceType: t3.medium
    desiredCapacity: 2
    volumeSize: 20
    ssh:
      allow: true

Use the following command to get kube-config.


aws eks update-kubeconfig --name=eso-test-cluster --region=eu-central-1

After these steps are complete, run the following command to verify.


kubectl get nodes

NAME                                              STATUS   ROLES    AGE     VERSION
ip-192-168-15-101.eu-central-1.compute.internal   Ready    <none>   3m31s   v1.22.12-eks-ba74326
ip-192-168-79-64.eu-central-1.compute.internal    Ready    <none>   3m31s   v1.22.12-eks-ba74326

 

As there are no errors, the EKS Cluster is ready for usage.

 

Installing the External Secrets Operator

The External Secrets Operator offers Helm Charts for deployment convenience, and I am going to use Helm for deploying the External Secrets Operator.

 

The following commands will deploy an External Secrets Operator to my EKS Cluster.

 


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=true \
   --set webhook.port=9443 



After the `external-secrets has been deployed successfully!` message, run the following command to verify external secret operator resources.

 


kubectl get pods -n external-secrets






Expected Output:

 

NAME                                                READY   STATUS    RESTARTS   AGE
external-secrets-7886b578b4-k27m4                   1/1     Running   0          2m32s
external-secrets-cert-controller-5578bf565f-nxhs7   1/1     Running   0          2m32s
external-secrets-webhook-84c7d457f4-r6cp6           1/1     Running   0          2m32s






IAM Roles For Service Accounts (IRSA)

For the external-secrets operator to be able to get secrets from the AWS Secrets Manager, I have to set a few configurations. You can manage the credentials for your applications with EKS's feature IRSA. This is similar to how Amazon EC2 instance profiles give credentials for Amazon EC2 instances. Instead of distributing AWS credentials or using the Amazon EC2 role, you can map an IAM role to a Kubernetes service account and set up your pods to use this service account. To use IRSA, it is mandatory to create an IAM OIDC Provider for the EKS cluster.

 

The following command will create an OIDC provider and associate it with my cluster.

 


$ eksctl utils associate-iam-oidc-provider --cluster=eso-test-cluster --approve --region eu-central-1

 

I am going to use eksctl to create a service account. The following command 'eksctl create iamserviceaccount' takes an IAM policy arn as an argument, creates an IAM role associated with the given policy, and maps a service account to that role.

 


eksctl create iamserviceaccount \
    --name esoblogsa \
    --namespace default \
    --cluster  \
    --role-name "esoBlogRole" \
    --attach-policy-arn <polıcy_arn> \
    --approve \
    --override-existing-serviceaccounts
</polıcy_arn>

 

I have already created my secret in the AWS Secrets Manager and an IAM policy that lets it be retrieved and decrypted. The following image shows a secret with the name test/eso/testSecret.

test/eso/testSecret

testesotestsecret

esoBlogSecretReadPolicy


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret"
            ],
            "Resource":≤secret_arn≥
        }
    ]
}




After these steps are completed, run the following command to verify the service account. 


$ kubectl describe sa esoblogsa

Name:                esoblogsa
Namespace:           default
Labels:              app.kubernetes.io/managed-by=eksctl
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::<account_number>:role/esoBlogRole
Image pull secrets:  <none>
Mountable secrets:   esoblogsa-token-9l2zj
Tokens:              esoblogsa-token-9l2zj
Events:              <none>

 

Sync External Secrets to the AWS Secrets Manager Secret

 

I am going to create a SecretStore that references AWS Secrets Manager with a service account that I have already created, 'esoblogsa'. Run the following command to create the SecretStore.


cat <<EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: eso-blog-secret-store
spec:
  provider:
    aws:
      service: SecretsManager
      region: eu-central-1
      auth:
        jwt:
          serviceAccountRef:
            name: esoblogsa
EOF

Run the following command to create an ExternalSecret. The Controller is going to create a secret with the name of "spec.target.name".


cat <<EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: blogdemo
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: eso-blog-secret-store
    kind: SecretStore
  target:
    name: esoblogsecret
    creationPolicy: Owner
  data:
  - secretKey: esoblog-test-password
    remoteRef:
      key: test/eso/testSecret #AWS secret name
      property: password #AWS secret key

Run the following command to verify the Kubernetes secret.


kubectl describe secret esoblogsecret

Name:         esoblogsecret
Namespace:    default
Labels:       
Annotations:  reconcile.external-secrets.io/data-hash: 2ffa008bbbf55886723ea27d84ed84c4

Type:  Opaque

Data
====
esoblog-test-password:  12 bytes

 

My ExternalSecret is synced to the secret stored in AWS Secrets Manager. The controller has already created the Kubernetes Secret and I can use that secret similar to how I use kubernetes secrets regularly. 

Destroy

Don’t forget to destroy your resources after all of these steps. Run the following commands to destroy your resources.

 


kubectl delete externalsecret.external-secrets.io/blogdemo
kubectl delete secretstore eso-blog-secret-store
eksctl delete iamserviceaccount \
    --name  \
    --namespace default \
    --cluster 
helm uninstall external-secrets -n external-secrets

#If you didn't use eksctl, you can pass this line.
eksctl delete cluster --name  --region 

Alternative solution

AWS Secrets Manager and Config Provider for Secret Store CSI Driver (ASCP) :Secrets from AWS Secrets Manager are exposed to your pods as a mounted storage volume via ASCP using the Secrets Store CSI driver. The CSI Secret Store driver runs as a DaemonSet and DaemonSets are not supported on Fargate.

Conclusion

The External Secrets Operator is a useful tool if you want to utilize your external secrets in your K8s cluster. Rather than other solutions, ESO is compatible with a wide range of cloud secret store services such as AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, etc., and for the EKS perspective, it is compatible with Fargate nodes too, which is not possible with ASCP.

 

>> Learn How to Run Amazon EKS Without an AWS Account

Cem Altuner

Cem is a cloud engineer at Kloia. He has studied Amazon Web Services and Kubernetes projects. He is also experimenting with serverless computing.