Skip to main content

Command Palette

Search for a command to run...

Integrating AWS Secrets Manager with EKS AWS

Published
7 min read

Integrating AWS Secrets Manager with Flask in EKS: A Comprehensive Guide

In this guide, we'll walk through the process of creating a Flask application that securely accesses secrets from AWS Secrets Manager when deployed in an Amazon EKS cluster. We'll cover everything from setting up the necessary IAM roles to deploying the application in your cluster.

Prerequisites

  • An existing EKS cluster with OIDC configured

  • kubectl configured to communicate with your EKS cluster

  • AWS CLI installed and configured

  • Docker installed on your local machine

Step 1: Create the Flask Application

First, let's create our Flask application that will display the secrets. Create a file named app.py with the following content:

from flask import Flask, render_template_string
import os
import json

app = Flask(__name__)

@app.route('/')
def index():
    secrets_file = '/mnt/secrets-store/myapp-secrets/myapp-secrets'
    if os.path.exists(secrets_file):
        with open(secrets_file, 'r') as f:
            secrets = json.load(f)
    else:
        secrets = {"error": "Secrets file not found"}

    html = '''
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Secrets Console</title>
        <style>
            body { font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; }
            h1 { color: #333; }
            pre { background-color: #f4f4f4; padding: 15px; border-radius: 5px; }
        </style>
    </head>
    <body>
        <h1>Secrets Console</h1>
        <pre>{{ secrets }}</pre>
    </body>
    </html>
    '''
    return render_template_string(html, secrets=json.dumps(secrets, indent=2))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

This Flask application reads the secrets from a file mounted by the AWS Secrets Store CSI Driver and displays them in a simple HTML page.

Step 2: Create a Dockerfile

Next, create a Dockerfile in the same directory as app.py:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

CMD ["python", "app.py"]

Create a requirements.txt file with the following content:

Flask==2.0.1
werkzeug==2.0.1

Step 3: Build and Push the Docker Image

Build the Docker image and push it to your preferred container registry. For this example, we'll use Amazon ECR:

# Create an ECR repository (if not already created)
aws ecr create-repository --repository-name flask-secrets-demo

# Authenticate Docker to your ECR registry
aws ecr get-login-password --region YOUR_REGION | docker login --username AWS --password-stdin YOUR_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com

# Build the Docker image
docker build -t flask-secrets-demo .

# Tag the image
docker tag flask-secrets-demo:latest YOUR_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/flask-secrets-demo:latest

# Push the image
docker push YOUR_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/flask-secrets-demo:latest

Replace YOUR_REGION and YOUR_ACCOUNT_ID with your AWS region and account ID.

Step 4: Set Up IAM Permissions

Create an IAM policy for Secrets Manager access:

aws iam create-policy --policy-name EKSSecretsManagerPolicy --policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": "arn:aws:secretsmanager:YOUR_REGION:YOUR_ACCOUNT_ID:secret:*"
    }
  ]
}'

Create an IAM role and service account:

eksctl create iamserviceaccount \
    --name secrets-access-sa \
    --namespace default \
    --cluster YOUR_CLUSTER_NAME \
    --attach-policy-arn arn:aws:iam::YOUR_ACCOUNT_ID:policy/EKSSecretsManagerPolicy \
    --approve \
    --override-existing-serviceaccounts

Replace YOUR_REGION, YOUR_ACCOUNT_ID, and YOUR_CLUSTER_NAME with your specific values.

  1. eksctl create iamserviceaccount: This is the main command to create an IAM role and associate it with a Kubernetes service account.

  2. --name secrets-access-sa: This specifies the name of the Kubernetes service account to be created or updated. In this case, it's named "secrets-access-sa".

  3. --namespace default: This indicates the Kubernetes namespace where the service account will be created. Here, it's the "default" namespace.

  4. --cluster YOUR_CLUSTER_NAME: This specifies the name of your EKS cluster where the service account will be created.

  5. --attach-policy-arn arn:aws:iam::YOUR_ACCOUNT_ID:policy/EKSSecretsManagerPolicy: This attaches the specified IAM policy to the IAM role that will be created and associated with the service account. The policy ARN should point to the policy you created earlier that grants permissions to access Secrets Manager.

  6. --approve: This flag automatically approves the creation of the IAM role without prompting for confirmation.

  7. --override-existing-serviceaccounts: This flag allows eksctl to update the service account if it already exists, ensuring that the latest configuration is applied.

Step 5: Install the AWS Secrets Store CSI Driver

If you haven't already installed the AWS Secrets Store CSI Driver, you can do so using Helm:

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm repo update
helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver --namespace kube-system
kubectl apply -f https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml 
#Adds the Helm repository for the Secrets Store CSI Driver to your local Helm setupStep

1.Adds the Helm repository for the Secrets Store CSI Driver to your local Helm setup

2.Updates your local Helm chart repository cache to ensure you have the latest versions of charts

3.Installs the Secrets Store CSI Driver in your cluster's kube-system namespace using Helm

4.Deploys the AWS provider for the Secrets Store CSI Driver, enabling it to work with AWS Secrets Manager

6. create. a secrer in aws secrets manager

aws secretsmanager create-secret --name myapp-secrets \
    --description "Secrets for my Flask application" \
    --secret-string '{"API_KEY":"my-super-secret-api-key","DATABASE_PASSWORD":"my-super-secret-db-password"}'

Step 7: Configure the SecretProviderClass

Create a file named secret-provider-class.yaml:

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: aws-secrets
spec:
  provider: aws
  parameters:
    objects: |
        - objectName: "myapp-secrets"
          objectType: "secretsmanager"
  1. apiVersion: secrets-store.csi.x-k8s.io/v1

    This specifies the API version for the SecretProviderClass resource. It's defined by the Secrets Store CSI Driver.

  2. kind: SecretProviderClass

    This defines the type of Kubernetes resource we're creating. SecretProviderClass is a custom resource introduced by the Secrets Store CSI Driver.

  3. metadata:

    name: aws-secrets

    This is the name of your SecretProviderClass. You'll reference this name when configuring pods to use these secrets.

  4. spec:

    This section defines the specifications for how secrets should be retrieved.

  5. provider: aws

    his specifies that we're using AWS as the provider for secrets. It tells the CSI driver to use the AWS provider we installed earlier.

  6. parameters:

    This section contains provider-specific parameters.

  7. objects: |

    This begins a multi-line yaml string that defines which secrets to retrieve.

  8. - objectName: "myapp-secrets"

    This specifies the name of the secret in AWS Secrets Manager. "myapp-secrets" should match the name of a secret you've created in AWS Secrets Manager.

  9. objectType: "secretsmanager"

    This indicates that the secret is stored in AWS Secrets Manager (as opposed to other AWS services like Parameter Store).

Apply this configuration:

kubectl apply -f secret-provider-class.yaml

Step 8: Deploy the Application

Create a file named deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-secrets-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flask-secrets-demo
  template:
    metadata:
      labels:
        app: flask-secrets-demo
    spec:
      serviceAccountName: secrets-access-sa
      containers:
      - name: flask-secrets-demo
        image: hackergovi/ekssecretmanager:v2
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: secrets-store-inline
          mountPath: "/mnt/secrets-store"
          readOnly: true
      volumes:
        - name: secrets-store-inline
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: "aws-secrets"
---
apiVersion: v1
kind: Service
metadata:
  name: flask-secrets-demo
spec:
  selector:
    app: flask-secrets-demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000
  type: LoadBalancer

Replace YOUR_ACCOUNT_ID and YOUR_REGION with your specific values.

note:- above i have used my custom image u can use yours &. dont forget to add service account to your deployment file

  1. volumeMounts:: This section in the container spec defines where the secrets will be mounted in the container.

    name: secrets-store-inline: This names the volume mount, matching the volume name defined later.

    mountPath: "/mnt/secrets-store": This is the path inside the container where the secrets will be mounted.

    readOnly: true: This ensures the secrets can't be modified by the container.

  2. volumes:: This section defines the volumes to be used by the pod.

    name: secrets-store-inline: This names the volume, matching the name in volumeMounts.

    csi:: This indicates we're using a CSI (Container Storage Interface) driver.

    driver: secrets-store.csi.k8s.io: This specifies we're using the Secrets Store CSI driver.

    readOnly: true: This makes the volume read-only for added security.

    volumeAttributes:: This section provides attributes for the CSI driver.

    secretProviderClass: "aws-secrets": This references the SecretProviderClass we created earlier, telling the CSI driver how to fetch the secrets.

Apply the deployment:

kubectl apply -f deployment.yaml

Step 9: Access the Application

Wait for the LoadBalancer to get an external IP:

kubectl get services flask-secrets-demo

Once you have the external IP, you can access your Flask application in a web browser using the IP address.

Conclusion

You've now successfully set up a Flask application that securely accesses secrets from AWS Secrets Manager when deployed in an Amazon EKS cluster. This setup ensures that your sensitive information is kept secure and can be easily rotated or updated without changing your application code.

Remember to follow best practices for secret management:

  • Regularly rotate your secrets

  • Use the principle of least privilege when granting access to secrets

  • Monitor and audit secret access

By leveraging AWS Secrets Manager and the AWS Secrets Store CSI Driver, you've added an extra layer of security to your EKS-based Flask application, ensuring that sensitive information is handled securely in your cloud-native environment.

More from this blog

dev ops

25 posts