Kubernetes External Secrets Operator

Kubernetes External Secrets Operator

July 22, 2024
167 views
Get tips and best practices from Develeap’s experts in your inbox

 

External Secrets Operator is an open source project targeting a common issue which is managing Kubernetes secrets (but not only!) in a GitOps yet cloud agnostic way. Its Kubernetes controller will monitor any ExternalSecret manifest applied to our cluster and leverage our secrets management system configuration to link, generate, and update Kubernetes secrets manifests needed for our deployments.

The Operator can integrate with many secret management solutions:

  • HashiCorp Vault
  • Azure Key Vault
  • AWS Secrets Manager

and many more.

The Problem:

Secrets are a substantial part of our applications, but their management could be a hassle. We’d like to follow GitOps principles, yet we can’t have them plain-text stored in our Git repository or even base64 encoded as Kubernetes secrets are. We’re already in the cloud, and would like to leverage our clouds’ secrets management system, however, we may extent to a multi-cloud deployment in the future.

Demo: External Secrets Operator to the rescue!

To demonstrate the strong features of using this operator, we’ll show you a quick and easy guide to getting started, and work our magic from a cloud stored secret, to an up-to-date kubernetes secret.

we will be using our favorite cloud — AWS:

  • EKS as our Kubernetes solution.
  • SecretsManager as our secrets management solution.
  • KMS to encrypt our secrets at rest and in transit.
  • BONUS: SSMParameterStore! Our operator integrates great with AWS Parameter Store as well, allowing better convenience for our developers.

Permissions

Since we’re top-notch Security Specialist Professionals, we start by creating an IAM Role in our AWS account, which will later be attached to our Operators’ service account. The process is also known as using IRSA which stands for IAM Role for Service Accounts.

This approach takes advantage of short-lived credentials instead of persistent AWS credentials, and manages permissions using AWS policies.

Create an IAM Policy

The following policy will give our future role permissions to decrypt the different versions of secrets stored in secrets manager, and will also work with SSM parameter store (bonus!).

  • In this example, we only allow a single course of action, which is to manage secrets in the cloud ONLY. However the operator is capable of updating secret values from within kubernetes — NOT RECOMMENDED.

“external-secrets-operator-demo-policy”:

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessToSecretsManager",
"Effect": "Allow",
"Action": [
"secretsmanager:ListSecrets",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:123456789012:secret:*"
]
},
{
"Sid": "AllowAccessToParameterStore",
"Effect": "Allow",
"Action": [
"ssm:GetParameters",
"ssm:GetParameter",
"ssm:GetParametersByPath"
],
"Resource": [
"arn:aws:ssm:us-east-1:123456789012:parameter/*"
]
},
{
"Sid": "AllowAccessToKMSDefaultKey",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:us-east-1:123456789012:key/02e225ec-2045-4811-bd8b-05a2a90f53bc"
]
}
]
}

Create an IAM Role

We will name this role “external-secrets-operator-demo-role” and attach the “external-secrets-operator-demo-policy” to it.

Also, we’ll make sure to set the Trust Policy appropriately, so our Kubernetes Service Account for the next steps, will be able to assume this role successfully.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "TrustMyRole",
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/FCEDA5370A14B25672159FC1FE731DFC"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/FCEDA5370A14B25672159FC1FE731DFC:aud": "sts.amazonaws.com",
"oidc.eks.us-east-1.amazonaws.com/id/FCEDA5370A14B25672159FC1FE731DFC:sub": "system:serviceaccount:demo:external-secrets-operator-demo-service-account"
}
}
}
]
}

IAM Role with Policy

Install the Operator

The Operator can be installed in many different way, direct YAML install, Helm chart installation, Terraform module, etc.

My absolute favorite is using the notorious aws-ia/eks-blueprints-addon Terraform module with a Terragrunt wrapper.

However, for simplicity, we’ll just use plan helm chart installation.

Let’s define our precious values in “values.yaml” first:

fullnameOverride: "external-secrets"
clusterName: external-secrets-operator-demo
clusterEndpoint: ${dependency.eks.outputs.cluster_endpoint}
serviceAccount:
name: external-secrets-operator-demo-service-account
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam:us-east-1:Z1234567890:role/external-secrets-operator-demo-roleNext, we can install the chart while feeding it our values file from previous step.

Quick tip: it’s best to work with explicit versions, as breaking changes might occur between different versions. For demo purposes only, we’ll use latest (‘helm-chart-0.9.4’ as of today).

helm repo add external-secrets https://charts.external-secrets.io
helm install --namespace demo --values ./values.yaml external-secrets external-secrets/external-secrets

Deploy a ClusterSecretStore

You could either deploy a SecretStore which is namespace scoped, or a ClusterSecretStore .

I like having a dedicated namespace for each controller / application / service, so i prefer having a centralized secret store.

To begin, we write our ClusterSecretStore manifest.

Since our operator works great with AWS SSMParameterStore as well, we might as well allow our developers to leverage both.

kind: ClusterSecretStore
metadata:
name: aws-secrets-manager
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-operator-demo-service-account
namespace: demo
---
kind: ClusterSecretStore
metadata:
name: aws-parameter-store
spec:
provider:
aws:
service: ParameterStore
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-operator-demo-service-account
namespace: demo

Let’s apply our manifests locally using `kubectl`:

kubectl apply — filename cluster-secret-stores.yaml

Validate our ClusterSecretStore s status using:

kubectl get clustersecretstores

Create our first ExternalSecret

We start of by creating a new secret in AWS Secrets Manager. Named external-secrets-operator-demo.

aws secretsmanager create-secret \
--name external-secrets-operator-demo \
--description "External Secrets Operator Demo." \
--secret-string "{\"foo\":\"bar\",\"password\":\"EXAMPLE-PASSWORD\"}"

Set the encryption:

  • we are using the default kms/ssm encryption key for demonstration purposes.

Write our “external-secret-manifest-demo.yaml” manifest

## Create an external secret lined to AWS Secrets Manager secret
## This will generate a kubernetes secret with the named "my-kubernetes-secret" in the demo namespace
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: my-external-secret
namespace: demo
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: my-kubernetes-secret # Secret name in k8s
creationPolicy: Owner

## You can get all of the secret content (recommended)
dataFrom:
- extract:
key: my-cloud-secret

## Or you can get specific fields
data:
- secretKey: my-kubernetes-secret-field # Name of the field to store inside the k8s secret
remoteRef:
key: my-cloud-secret # Our AWS SecretsManager secret-name goes here
property: password # Retrieve the password field
  • It’s best practice to follow GitOps principles, and store this manifest in your gitops repository, which is monitored by ArgoCD.

Just for demonstration purposes, we’ll apply manually.

kubectl apply — filename external-secret-manifest-demo.yaml

Validate our ExternalSecret status using:

kubectl get externalsecret my-external-secret — namespace demo

Kubernetes secret

Let’s see the generated Kubernetes secret created for us:

kubectl get secret -n demo

Kubernetes secret

We are all set!

Links and references:

We’re Hiring!
We’re Hiring!
Develeap is looking for talented DevOps engineers who want to make a difference in the world.