Triển Khai IRSA Trên EKS: Hướng Dẫn Chi Tiết Về OIDC Provider & IAM Trust Policy

KiloKilo
5 min read

Triển Khai IRSA Trên EKS: Hướng Dẫn Chi Tiết Về OIDC Provider & IAM Trust Policy

Trong hệ sinh thái Kubernetes trên AWS, việc quản lý quyền truy cập vào các tài nguyên AWS (như S3, DynamoDB, SQS, …) cho Pod là một nhiệm vụ quản trị quan trọng. AWS cung cấp cơ chế IRSA (IAM Roles for Service Accounts) để Pod trong EKS có thể assume IAM Role an toàn và linh hoạt.

Bài viết này sẽ đưa bạn đi từ những khái niệm cơ bản như OIDC Provider, JWT Token, đến việc viết IAM Trust Policy an toàn chỉ cho phép Pod của một Service Account cụ thể assume role.

🔹 Service Account là gì?

Trong Kubernetes, có 2 loại tài khoản dùng để xác thực:

  • User Account: dành cho người dùng thực (con người).

  • Service Account (SA): dành cho các pod, deployment, hoặc controller trong cluster khi chúng cần tương tác với Kubernetes API.

Ví dụ: Một Pod muốn gọi Kubernetes API để đọc secret hoặc xem các pod khác — nó sẽ dùng service account để xác thực.

🔹 Tại sao cần Service Account?

Mỗi pod trong Kubernetes có thể cần truy cập API server để thực hiện hành động như:

  • Lấy thông tin các pod khác (để service discovery).

  • Gọi API để tạo/update resource (ví dụ: job, configmap).

  • Tải secret/credential để kết nối dịch vụ ngoài.

Vì lý do bảo mật, bạn nên giới hạn quyền truy cập theo principle of least privilege (chỉ cấp đúng những gì cần).

🔹 Cách hoạt động

Mặc định, khi bạn tạo một Pod mà không chỉ rõ Service Account, Kubernetes sẽ tự động gán default service account trong namespace đó cho Pod.

Khi Pod khởi chạy:

  • Nó được mount 1 token ở đường dẫn /var/run/secrets/kubernetes.io/serviceaccount/token.

  • Token này là một JWT có thể dùng để gọi đến Kubernetes API server.

🔹 Tạo và gán Service Account

Tạo một Service Account

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  namespace: default

Gán vào Pod

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  serviceAccountName: my-service-account
  containers:
  - name: mycontainer
    image: busybox
    command: ["sleep", "3600"]

🔹 Gán quyền cho Service Account với RBAC

Mặc định, Service Account không có quyền gì cả. Bạn cần tạo Role/ClusterRole và gán chúng bằng RoleBinding/ClusterRoleBinding.

Ví dụ: Cấp quyền đọc pod

# Tạo Role (giới hạn trong namespace)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
# Gán Role cho Service Account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-binding
  namespace: default
subjects:
- kind: ServiceAccount
  name: my-service-account
  namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

🔹 Thực hành kiểm tra

Bạn có thể chạy pod dùng kubectl proxy hoặc mount kubectl vào trong pod rồi dùng biến môi trường:

export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc/api

🔹 Tổng kết

Thành phầnMục đích
ServiceAccountĐại diện cho một pod hay app trong cluster
Role / ClusterRoleXác định các quyền
RoleBinding / ClusterRoleBindingGán Role cho Service Account

Tổng Quan Về IRSA

IRSA cho phép mỗi pod trong Kubernetes assume một IAM Role mà không cần lồng AWS credentials trong image hay inject environment variables.

Mô Hình Hoạt Động:

  1. Pod dùng Service Account được gán annotation IAM Role.

  2. Kubelet mount token JWT OIDC vào pod.

  3. Pod gọi lệnh AssumeRoleWithWebIdentity đến AWS STS.

  4. AWS dùng OIDC Provider để xác thực token JWT.

  5. Nếu token hợp lệ và policy cho phép, AWS trả về temporary credentials.

OIDC Provider là gì?

OIDC (OpenID Connect) là chuẩn xác thực danh tính dựa trên OAuth2, sử dụng rộng rãi để trao đổi token xác thực giữa các hệ thống.

Trong EKS, AWS cần biết token JWT kia có được Kubernetes ký và có hợp lệ không. Đó là lý do OIDC Provider tồn tại trong IAM.

OIDC Provider trong EKS có dạng:

https://oidc.eks.<region>.amazonaws.com/id/<eks-cluster-id>

Khi bạn chạy:

eksctl utils associate-iam-oidc-provider \
  --region <region> \
  --cluster <cluster-name> \
  --approve

AWS sẽ tự đăng ký OIDC Provider trong IAM.

JWT Token Trong IRSA

Pod được mount token từ Service Account:

{
  "sub": "system:serviceaccount:default:my-service-account",
  "aud": "sts.amazonaws.com",
  "iss": "https://oidc.eks.ap-southeast-1.amazonaws.com/id/ABCD1234EFGH"
}

Các trường quan trọng:

  • sub: Service Account nào dùng token.

  • aud: phải là sts.amazonaws.com

  • iss: issuer, phải khớp với OIDC Provider trong IAM

Tạo IAM Role Cho Service Account

IAM Role cho Pod phải có trust policy chi tiết:

Mẫu Trust Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/oidc.eks.ap-southeast-1.amazonaws.com/id/ABCD1234EFGH"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.ap-southeast-1.amazonaws.com/id/ABCD1234EFGH:sub": "system:serviceaccount:default:my-service-account",
          "oidc.eks.ap-southeast-1.amazonaws.com/id/ABCD1234EFGH:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}

Giải thích các thành phần

TrườngÝ nghĩa
Principal.FederatedCho phép OIDC Provider đại diện pod gọi sts:AssumeRoleWithWebIdentity
ActionChỉ cho phép assume role qua OIDC (sts:AssumeRoleWithWebIdentity)
Condition.StringEqualsRất quan trọng: chỉ cho phép SA cụ thể (sub) và đúng aud (người nhận là sts.amazonaws.com)
  • sub bắt buộc có dạng:
    system:serviceaccount:<namespace>:<serviceaccount-name>

  • Nếu bạn bỏ qua phần "Condition" thì mọi SA trong toàn bộ cluster có thể assume IAM Role => rất nguy hiểm!

Gắn Role vào Service Account:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  namespace: default
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/my-irsa-role

Sau khi khai báo, bất kỳ Pod nào dùng SA này sẽ tự động có AWS credentials.

Kiểm Tra Token Trong Pod

Bạn có thể exec và decode token:

kubectl exec -it <pod> -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | \
  jq -R 'split(".") | .[1] | @base64d | fromjson'

Sẽ xuất ra payload JWT.

✅ Tóm tắt quy trình bảo mật với OIDC Trust Policy

  1. EKS cấp token JWT có sub = system:serviceaccount:ns:name

  2. Pod gửi token đến AWS STS để assume IAM Role

  3. IAM Role kiểm tra:

    • Token có đúng issuer (OIDC)

    • Token có đúng sub

    • Token có đúng aud

  4. Nếu đúng, cấp temporary credentials

Kết Luận

Việc sử dụng IRSA giúp:

  • Tách biệt quyền truy cập AWS theo pod.

  • Không cần embed AWS credentials.

  • Tuân thủ principle of least privilege.

OIDC Provider trong EKS là gốc của trust chain, cùng với JWT token từ Service Account và IAM Trust Policy chi tiết sẽ đảm bảo bạn có hệ thống an toàn và linh hoạt.

0
Subscribe to my newsletter

Read articles from Kilo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kilo
Kilo