or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

alb-controller.mdauth.mdcluster.mdfargate.mdindex.mdkubectl-provider.mdkubernetes-resources.mdnode-groups.mdservice-accounts.mdutilities.md
tile.json

service-accounts.mddocs/

Service Accounts

Kubernetes service accounts with IAM role binding (IRSA) providing secure AWS service access from pods through IAM roles for service accounts.

Capabilities

ServiceAccount Class

Kubernetes service account with associated IAM role for secure AWS API access.

/**
 * Kubernetes service account with IAM role (IRSA)
 */
class ServiceAccount extends Construct implements iam.IPrincipal {
  constructor(scope: Construct, id: string, props: ServiceAccountProps);
  
  /** Associated IAM role */
  readonly role: iam.IRole;
  /** Service account name */
  readonly serviceAccountName: string;
  /** Service account namespace */
  readonly serviceAccountNamespace: string;
  /** Assume role action */
  readonly assumeRoleAction: string;
  /** Grant principal */
  readonly grantPrincipal: iam.IPrincipal;
  /** Principal ARN */
  readonly principalArn: string;
  
  /** Add policy statement to the service account's IAM role */
  addToPrincipalPolicy(statement: iam.PolicyStatement): iam.AddToPrincipalPolicyResult;
  
  /** @deprecated Use addToPrincipalPolicy instead */
  addToPolicy(statement: iam.PolicyStatement): boolean;
}

/**
 * Service account properties
 */
interface ServiceAccountProps extends ServiceAccountOptions {
  /** EKS cluster */
  readonly cluster: ICluster;
}

/**
 * Service account configuration options
 */
interface ServiceAccountOptions {
  /** Service account name */
  readonly name?: string;
  /** Kubernetes namespace */
  readonly namespace?: string;
  /** Service account annotations */
  readonly annotations?: { [key: string]: string };
  /** Service account labels */
  readonly labels?: { [key: string]: string };
  /** IAM role to associate */
  readonly role?: iam.IRole;
}

Usage Examples:

import * as eks from "@aws-cdk/aws-eks";
import * as iam from "@aws-cdk/aws-iam";
import * as s3 from "@aws-cdk/aws-s3";

// Basic service account
const serviceAccount = cluster.addServiceAccount("MyServiceAccount", {
  name: "my-service-account",
  namespace: "default",
});

// Grant S3 access to the service account
const bucket = new s3.Bucket(this, "MyBucket");
bucket.grantReadWrite(serviceAccount);

// Service account with custom IAM role
const customRole = new iam.Role(this, "CustomRole", {
  assumedBy: new iam.WebIdentityPrincipal(
    cluster.openIdConnectProvider.openIdConnectProviderArn,
    {
      "StringEquals": {
        [`${cluster.clusterOpenIdConnectIssuer}:sub`]: "system:serviceaccount:default:custom-sa",
        [`${cluster.clusterOpenIdConnectIssuer}:aud`]: "sts.amazonaws.com",
      },
    }
  ),
});

const customServiceAccount = cluster.addServiceAccount("CustomServiceAccount", {
  name: "custom-sa",
  namespace: "default", 
  role: customRole,
});

// Service account with specific permissions
const s3ServiceAccount = cluster.addServiceAccount("S3ServiceAccount", {
  name: "s3-reader",
  namespace: "app",
  labels: {
    "app": "data-processor",
    "component": "reader",
  },
});

s3ServiceAccount.addToPrincipalPolicy(new iam.PolicyStatement({
  effect: iam.Effect.ALLOW,
  actions: [
    "s3:GetObject",
    "s3:ListBucket",
  ],
  resources: [
    "arn:aws:s3:::my-data-bucket",
    "arn:aws:s3:::my-data-bucket/*",
  ],
}));

Pod Integration

To use the service account in a pod:

apiVersion: v1
kind: Pod
metadata:
  name: aws-cli-pod
  namespace: default
spec:
  serviceAccountName: my-service-account  # Links to the created service account
  containers:
    - name: aws-cli
      image: amazon/aws-cli:latest
      command: ["aws", "s3", "ls"]  # Will use the service account's IAM role

IRSA (IAM Roles for Service Accounts)

IRSA provides the following benefits:

  1. Fine-grained permissions: Each pod can have different AWS permissions
  2. No node-level permissions: No need to grant broad permissions to worker nodes
  3. Audit trail: AWS CloudTrail shows which service account made API calls
  4. Credential rotation: AWS STS handles credential rotation automatically

IRSA Architecture:

/**
 * IRSA trust relationship configuration
 */
interface IRSATrustPolicy {
  /** OIDC provider ARN */
  readonly openIdConnectProviderArn: string;
  /** Service account subject */
  readonly subject: string;
  /** OIDC audience */
  readonly audience: string;
}

Service Account Annotations

The service account is automatically annotated with the IAM role ARN:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  namespace: default
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/MyServiceAccountRole

Best Practices

  1. Principle of Least Privilege: Grant only the minimum permissions required
  2. Namespace Isolation: Use different service accounts for different namespaces
  3. Service-Specific Accounts: Create dedicated service accounts for each service
  4. Regular Auditing: Review and audit service account permissions regularly
// Example: Service account for different environments
const prodServiceAccount = cluster.addServiceAccount("ProdServiceAccount", {
  name: "app-service-account", 
  namespace: "production",
  labels: {
    "environment": "production",
    "app": "web-api",
  },
});

const stagingServiceAccount = cluster.addServiceAccount("StagingServiceAccount", {
  name: "app-service-account",
  namespace: "staging", 
  labels: {
    "environment": "staging",
    "app": "web-api",
  },
});

// Grant different permissions based on environment
prodBucket.grantRead(prodServiceAccount);
stagingBucket.grantReadWrite(stagingServiceAccount);