The problem -- we have a ci process that will need access to one namespace in an EKS cluster and must be able to deploy the new container as well as roll it back.
We need to establish two things in relation to our interactions with EKS:
At the 10,000 foot view, AuthN gets solved using an IAM user and then we map that IAM user to internal EKS RBAC groups and bindings.
For our specific use-case, we are using the IAM user to not just get access but also to generate our kubeconfig in our CI environment (thus the extra policy we tack on). In the general case, if you have a copy of kubeconfig that you can make available to your CI system in some other manner -- feel free and you won't need this policy.
Create a new IAM policy named: EKS_CICD_User_Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"eks:DescribeCluster"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
This will allow you to request a kubeconfig later on with the aws-cli. That done, we want to create a user with credentials that we can store and use in the CI environment -- known as programatic access. This is well documented and standardized. Create this user as you will and attach the EKS_CICD_User_Policy
. The name we're going to use for this user is my-test-iam-user
(which is a horrible name but it'll make the later examples clearer... hopefully).
You should now have an access_key_id
and a secret_access_key
for this user.
We need to create an entity to take action on resources within the cluster. First off, do we create a k8s serviceaccount
or a user
? Here is the answer from the CNCF blog:
One topic that many Kubernetes users struggle with is the concept of subjects, but more specifically the difference between regular users and ServiceAccounts. In theory it looks simple:
Users: These are global, and meant for humans or processes living outside the cluster.
ServiceAccounts: These are namespaced and meant for intra-cluster processes running inside pods.
User
it is.
We're going to create an RBAC rolebinding for a user constrained to one k8s namespace that will limit what our user can do in the k8s cluster. We'll create the namespace and the initial deployment of our application out of band.
Here's the namespace create statement so we have it in front of us to use in the rolebinding.
kubectl create namespace my-test-ns
Next we'll create the Role and bindings that correlate our user to that role:
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: my-test-role
namespace: my-test-ns
rules:
- apiGroups: ["extensions", "apps"]
resources: ["replicasets"]
verbs: ["list", "get", "create", "update", "delete", "watch", "patch"]
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["list", "get", "create", "update", "delete", "watch", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-test-user-role-binding
namespace: my-test-ns
roleRef:
kind: Role
name: my-test-role
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: User
name: my-test-user
Man, that's a lot of stuff, right? Callouts:
Now we have an IAM user and policy on one hand and then a Role and Rolebinding on the other. We have as our last step: tying the two together.
There are two broad ways to do this mapping: via kubectl
or via eksctl
.
Via kubectl, you'll be making changes to a configmap named aws_auth
that is created by AWS for this very purpose. You can either edit the configmap or pull it down, make changes, and replace.
In place:
kubectl edit configmap aws-auth -n kube-system
or dumping locally and then reapplying after you make the change:
kubectl get configmap aws-auth -n kube-system -o yaml > aws-auth.yaml
The configmap will look like this. You want to edit and add an entry to the mapUsers
section as you see below:
apiVersion: v1
data:
mapRoles: |
# <snip -- this is internal stuff. don't touch it>
mapUsers: |
- userarn: arn:aws:iam::123412341234:user/my-test-iam-user
username: my-test-user
groups:
- my-test-role
Just to be explicit as to where the values come from:
my-test-iam-user
my-test-user
my-test-role
The third way to map your IAM user to internal EKS user is via the eksctl
tool as detailed here and is basically:
eksctl create iamidentitymapping --cluster my-cluster-1 --arn arn:aws:iam::123412341234:user/my-test-iam-user --group my-test-role --username my-test-user
That's it. You're ready to roll.