[AWS] How to use EKS IRSA in the most vulnerable way

rex.chun
4 min readJun 3, 2023

--

https://www.oursundayvisitor.com/what-did-jesus-mean-by-stars-falling-from-the-sky/

TL;DR

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/CLUSTER_ID"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"oidc.eks.us-east-2.amazonaws.com/id/CLUSTER_ID:sub": "system:serviceaccount:*:*"
}
}
}
]
}

Stars(*) are falling.

What is IRSA?

IRSA (IAM Roles for Service Accounts) is a feature in EKS (Elastic Kubernetes Service) that allows pods to assume roles and perform actions on AWS resources. This functionality is not limited to EKS and can be used in other environments as well. When examining IRSA in more detail, it operates in the following sequence:

webhooks:
...<SNIP>...
- operations: [ "CREATE" ]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
sideEffects: None
admissionReviewVersions: ["v1beta1"]
  • Verify that the ServiceAccount of the pod has the following types of values. (annotations: eks.amazonaws.com …<SNIP>…)
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME
name: rex
namespace: rex
  • After that, mount the following environment variables and files on the pod.
apiVersion: v1
items:
- apiVersion: v1
kind: Pod
...<SNIP>...
spec:
containers:
- env:
...<SNIP>...
- name: AWS_STS_REGIONAL_ENDPOINTS
value: regional
- name: AWS_DEFAULT_REGION
value: us-east-2
- name: AWS_REGION
value: us-east-2
- name: AWS_ROLE_ARN
value: arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME
- name: AWS_WEB_IDENTITY_TOKEN_FILE
value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
...<SNIP>...
- mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
name: aws-iam-token
readOnly: true
volumes:
- name: aws-iam-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: sts.amazonaws.com
expirationSeconds: 86400
path: token
...<SNIP>...
  • Subsequent operations are automatically handled by the AWS SDK, and the process is depicted in the following picture.
https://aws.amazon.com/ko/blogs/containers/diving-into-iam-roles-for-service-accounts/

What’s the problem?

To find out why “*” is a problem, you need to know how it works.

Token for sts:AssumeRoleWithWebIdentity

When decoding the token, various values are obtained, including the following: ‘sub’ contains the service account, ‘aud’ contains ‘sts.amazonaws.com’, and ‘iss’ contains the OIDC endpoint of the EKS cluster.

JWT Token

A JSON Web Token (JWT) is a token used to ensure the integrity of specific data by encrypting a signature value that can be decrypted with a public key to verify that the token has not been tampered with.

  • HEADER: Contains the signature algorithm and key ID.
  • PAYLOAD: Contains non-sensitive data that needs to be transmitted.
  • VERIFY SIGNATURE: Ensures that the PAYLOAD has not been tampered with.

However, a problem arises here. AWS only verifies the validity of the JWT token, but it does not guarantee consistency between the token file and the actual role specified in the service account.

Let’s examine this in more detail.

Hack the IRSA!

First, let’s assume a normal situation.

Normal trust policy

By specifying the conditions, AWS allows the acceptance of service accounts coming from a specific OIDC endpoint. Let’s try assuming the role of the service account using the sts:AssumeRoleWithWebIdentity API.

rex:~/environment $ aws sts assume-role-with-web-identity \
--role-arn arn:aws:iam::ACCOUNT_ID:role/eks-workshop-carts-dynamo \
--role-session-name test --web-identity-token eyJhbGciOiJSUzI1<SNIP>
{
"Credentials": {
"AccessKeyId": "ASIA<SNIP>",
"SecretAccessKey": "KZ9V<SNIP>",
"SessionToken": "IQoJb<SNIP>",
"Expiration": "2023-06-03T01:00:43+00:00"
},
"SubjectFromWebIdentityToken": "system:serviceaccount:carts:carts",
"AssumedRoleUser": {
"AssumedRoleId": "AROAWU22AXDEAGQGMY3XZ:test",
"Arn": "arn:aws:sts::ACCOUNT_ID:assumed-role/eks-workshop-carts-dynamo/test"
},
"Provider": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/9278920BDA929A8A54E92E18A4DECB2A",
"Audience": "sts.amazonaws.com"
}

I have made API calls from a custom-configured Cloud9 environment. Do you notice anything unusual? Even though the API was called from outside of EKS, I was able to successfully obtain the credentials. Based on this, we can reach the following conclusion.

1. With just the token and role ARN, it is possible to assume the role from anywhere.

Now, let’s try using the “*” that I showed you at the beginning. The vulnerable trust policy is as follows.

Now, let’s try assuming another role using the same token.

rex:~/environment $ aws sts assume-role-with-web-identity \
--role-arn arn:aws:iam::ACCOUNT_ID:role/rextest1234 --role-session-name test \
--web-identity-token eyJhbGciOiJSUzI1<SNIP>
{
"Credentials": {
"AccessKeyId": "ASIA<SNIP>",
"SecretAccessKey": "HJ8N<SNIP>",
"Expiration": "2023-06-03T01:06:31+00:00"
},
"SubjectFromWebIdentityToken": "system:serviceaccount:carts:carts",
"AssumedRoleUser": {
"AssumedRoleId": "AROAWU22AXDEPTXHKPKQC:test",
"Arn": "arn:aws:sts::ACCOUNT_ID:assumed-role/rextest1234/test"
}, "Provider": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/9278920BDA929A8A54E92E18A4DECB2A",
"Audience": "sts.amazonaws.com"
}

OMG! We can see that the assumption of the role is possible regardless of the token’s PAYLOAD. This leads us to the second conclusion.

2. The vulnerable trust policy is risky regardless of the token’s PAYLOAD and the role-arn specified in the service account.

Conclusion

  1. With just the token and role ARN, it is possible to assume the role from anywhere.
  2. The vulnerable trust policy is risky regardless of the token’s PAYLOAD and the role-arn specified in the service account.
  3. So, you should specify the namespace and service account in trust policy.

In addition, there are other points to be cautious about when using IRSA, but we will conclude our discussion here for today.

Thank you for reading the lengthy text.

References

  1. https://docs.aws.amazon.com/eks/latest/userguide/authenticate-oidc-identity-provider.html
  2. https://www.eksworkshop.com/docs/security/iam-roles-for-service-accounts/
  3. https://aws.amazon.com/ko/blogs/containers/diving-into-iam-roles-for-service-accounts/
  4. https://github.com/aws/amazon-eks-pod-identity-webhook

--

--