2025-12-11 04:39:25 -05:00
2025-12-11 04:39:25 -05:00
2025-12-11 04:39:25 -05:00
2025-12-11 04:39:25 -05:00
2025-12-10 10:43:57 -05:00
2025-12-10 10:43:57 -05:00
2025-12-10 10:43:57 -05:00
2025-12-11 04:39:25 -05:00
2025-12-10 10:43:57 -05:00

IRSA Mutating Admission Webhook for Kubernetes

This webhook implements IAM Roles for Service Accounts (IRSA) for Kubernetes clusters, allowing pods to assume AWS IAM roles using projected service account tokens.

Features

  • Automatically injects AWS credentials configuration into pods
  • Uses projected service account tokens with custom audience
  • Supports multiple containers and init containers
  • Follows security best practices
  • No external dependencies beyond Kubernetes API

How It Works

When a pod is created, the webhook:

  1. Extracts the ServiceAccount name from the pod spec
  2. Fetches the ServiceAccount from the Kubernetes API
  3. Checks for the vultr.com/role-arn annotation
  4. If present, mutates the pod to inject:
    • Environment Variables:
      • AWS_ROLE_ARN: The IAM role ARN from the annotation
      • AWS_WEB_IDENTITY_TOKEN_FILE: Path to the projected token
      • AWS_STS_REGIONAL_ENDPOINTS: Set to "regional"
    • Volume: A projected ServiceAccount token volume with audience "vultr"
    • Volume Mounts: Mounts the token at /var/run/secrets/vultr.com/serviceaccount

Prerequisites

  • Kubernetes 1.20+ (for projected service account tokens)
  • kubectl configured to access your cluster
  • OpenSSL (for certificate generation)
  • Go 1.24+ (for building from source)

Quick Start

1. Build the Docker Image

docker build -t your-registry/irsa-webhook:latest .
docker push your-registry/irsa-webhook:latest

Update deploy.yaml with your image location.

2. Generate TLS Certificates

The webhook requires TLS certificates to communicate with the Kubernetes API server:

chmod +x generate-certs.sh
./generate-certs.sh

This script will:

  • Generate a self-signed CA and certificate
  • Create a Kubernetes secret with the certificates
  • Update the MutatingWebhookConfiguration with the CA bundle

3. Deploy the Webhook

kubectl apply -f deploy.yaml

This creates:

  • Namespace: irsa-system
  • ServiceAccount with RBAC permissions
  • Deployment with 2 replicas
  • Service
  • MutatingWebhookConfiguration

4. Verify Deployment

kubectl get pods -n irsa-system
kubectl logs -n irsa-system -l app=irsa-webhook

Usage

Annotate ServiceAccount

To enable IRSA for a ServiceAccount, add the vultr.com/role-arn annotation:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  namespace: default
  annotations:
    vultr.com/role-arn: "arn:aws:iam::123456789012:role/my-app-role"

Deploy a Pod

Any pod using this ServiceAccount will automatically receive the AWS configuration:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  namespace: default
spec:
  serviceAccountName: my-app
  containers:
  - name: app
    image: amazon/aws-cli:latest
    command: ["sleep", "3600"]

Verify Injection

Check that the pod has the injected configuration:

# Check environment variables
kubectl exec my-app -- env | grep AWS

# Check volume mount
kubectl exec my-app -- ls -la /var/run/secrets/vultr.com/serviceaccount

# Test AWS credentials
kubectl exec my-app -- aws sts get-caller-identity

Configuration

Environment Variables

The webhook supports the following environment variables:

  • TLS_CERT_PATH: Path to TLS certificate (default: /etc/webhook/certs/tls.crt)
  • TLS_KEY_PATH: Path to TLS private key (default: /etc/webhook/certs/tls.key)
  • PORT: HTTPS port to listen on (default: 8443)

Webhook Configuration

Edit the MutatingWebhookConfiguration in deploy.yaml:

  • failurePolicy: Set to Fail for production to block pods if webhook is unavailable
  • timeoutSeconds: Adjust timeout based on cluster performance
  • namespaceSelector: Control which namespaces are affected

Security Considerations

  1. Least Privilege: The webhook ServiceAccount only has permissions to read ServiceAccounts
  2. TLS: All communication is encrypted using TLS 1.2+
  3. Non-root: Container runs as non-root user (65532)
  4. Read-only filesystem: Container has read-only root filesystem
  5. No privilege escalation: Security context prevents privilege escalation

Troubleshooting

Webhook Not Mutating Pods

  1. Check webhook logs:

    kubectl logs -n irsa-system -l app=irsa-webhook
    
  2. Verify MutatingWebhookConfiguration:

    kubectl get mutatingwebhookconfiguration irsa-webhook -o yaml
    
  3. Check if ServiceAccount has the annotation:

    kubectl get sa <service-account-name> -o yaml
    

Certificate Issues

If you see TLS errors, regenerate certificates:

./generate-certs.sh
kubectl rollout restart deployment -n irsa-system irsa-webhook

RBAC Permissions

If webhook can't fetch ServiceAccounts, verify RBAC:

kubectl auth can-i get serviceaccounts --as=system:serviceaccount:irsa-system:irsa-webhook --all-namespaces

Development

Local Testing

You can test the webhook logic locally:

package main

import (
    "testing"
    corev1 "k8s.io/api/core/v1"
)

func TestGeneratePatches(t *testing.T) {
    ws := &WebhookServer{}
    pod := &corev1.Pod{
        Spec: corev1.PodSpec{
            Containers: []corev1.Container{
                {Name: "test"},
            },
        },
    }

    patches, err := ws.generatePatches(pod, "arn:aws:iam::123456789012:role/test")
    if err != nil {
        t.Fatalf("Failed to generate patches: %v", err)
    }

    if len(patches) == 0 {
        t.Error("Expected patches to be generated")
    }
}

Building from Source

go mod download
go build -o webhook main.go

Architecture

┌─────────────┐
│ Kubernetes  │
│ API Server  │
└──────┬──────┘
       │
       │ AdmissionReview Request
       │
       ▼
┌─────────────────┐
│ IRSA Webhook    │
│                 │
│ 1. Parse Pod    │
│ 2. Get SA       │◄────┐
│ 3. Check Anno   │     │
│ 4. Gen Patches  │     │
└─────────────────┘     │
                        │
                  ┌─────┴──────┐
                  │ K8s API    │
                  │ (Get SA)   │
                  └────────────┘

License

MIT

Contributing

Contributions welcome! Please ensure:

  • Code follows Go best practices
  • Add tests for new functionality
  • Update documentation as needed
Description
No description provided
Readme 38 MiB
Languages
Go 60.3%
Makefile 19%
Shell 17.9%
Dockerfile 2.8%