Static Keys: S3 Vault Hunters: Hardcoding AWS Keys in K8s
Luke Hebert
- 3 minutes read - 495 wordsDeploying S3 object storage in Kubernetes with the AWS S3 CSI driver involves configuring credentials, defining a StorageClass, creating a PersistentVolumeClaim, and mounting the volume into pods or deployments. The setup supports both PVC-based and direct CSI volume mounting, and works with AWS S3 as well as S3-compatible alternatives like MinIO.
Key Components
- Secret: Stores S3 credentials securely
- StorageClass: Defines how S3 volumes should be provisioned using the S3 CSI driver
- PersistentVolumeClaim: Requests storage from the S3 StorageClass
- Pod/Deployment: Shows how to mount and use the S3 storage
Note
- CSI Driver Required: You’ll need to install the AWS S3 CSI driver in your cluster first
- Credentials: Replace the placeholder credentials with your actual S3 access keys
- Bucket Configuration: Update the bucket name and region to match your S3 setup
- Endpoint: Use the appropriate S3 endpoint (AWS S3, MinIO, etc.)
Installation of S3 CSI Driver
kubectl apply -k "github.com/kubernetes-sigs/aws-s3-csi-driver/deploy/kubernetes/overlays/stable/?ref=main"Alternative Approaches
- Use the AWS EFS CSI driver if you need true shared filesystem semantics
- Consider using S3 via application-level SDKs rather than filesystem mounts for better performance
- For object storage access patterns, direct API calls might be more appropriate than filesystem mounting
The examples below show both PVC-based and direct CSI volume mounting approaches, plus a deployment example for scalable applications.
Example
# Secret for S3 credentials
apiVersion: v1
kind: Secret
metadata:
name: s3-secret
namespace: default
type: Opaque
stringData:
accesskey: "your-access-key-id"
secretkey: "your-secret-access-key"---
# Storage Class for S3
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: s3-storage-class
provisioner: s3.csi.aws.com
parameters:
mounter: geesefs
bucket: "your-bucket-name"
region: "us-east-1"
endpoint: "https://s3.amazonaws.com"
# For non-AWS S3-compatible storage (like MinIO)
# endpoint: "http://minio-service:9000"
reclaimPolicy: Delete
allowVolumeExpansion: true---
# Persistent Volume Claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: s3-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: s3-storage-class---
# Example Pod using the S3 storage
apiVersion: v1
kind: Pod
metadata:
name: s3-pod
namespace: default
spec:
containers:
- name: app-container
image: nginx:latest
volumeMounts:
- name: s3-volume
mountPath: /data
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-secret
key: accesskey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-secret
key: secretkey
volumes:
- name: s3-volume
persistentVolumeClaim:
claimName: s3-pvc---
# Alternative: Direct S3 volume mount (without PVC)
apiVersion: v1
kind: Pod
metadata:
name: s3-direct-pod
namespace: default
spec:
containers:
- name: app-container
image: nginx:latest
volumeMounts:
- name: s3-direct-volume
mountPath: /s3data
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-secret
key: accesskey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-secret
key: secretkey
volumes:
- name: s3-direct-volume
csi:
driver: s3.csi.aws.com
volumeAttributes:
bucket: "your-bucket-name"
region: "us-east-1"
nodePublishSecretRef:
name: s3-secret
namespace: default---
# Deployment example with S3 storage
apiVersion: apps/v1
kind: Deployment
metadata:
name: s3-app-deployment
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: s3-app
template:
metadata:
labels:
app: s3-app
spec:
containers:
- name: app
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: s3-storage
mountPath: /var/www/html
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-secret
key: accesskey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-secret
key: secretkey
volumes:
- name: s3-storage
persistentVolumeClaim:
claimName: s3-pvc