2023-05-15 15:25:28 -07:00

232 lines
8.8 KiB
Markdown

---
date: "2020-06-02"
title: "Access Control for Pods on Amazon EKS"
authors: ["mike-metral"]
tags: ["aws", "Kubernetes", "eks", "rbac"]
meta_desc: "Amazon EKS clusters can use IAM roles and policies for Pods to assign fine-grained access control of AWS services."
meta_image: cluster.png
---
Amazon [EKS][aws-eks] clusters can use [IAM][aws-iam] roles and policies for Pods
to assign fine-grained access control of AWS services. The AWS IAM entities map into Kubernetes
[RBAC][k8s-rbac] to configure the permissions of Pods that work with AWS
services.
Together, AWS IAM and Kubernetes RBAC enable least-privileged access for your
apps, scoped to the appropriate policies and user requirements.
[k8s-rbac]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
<!--more-->
## Overview
In <100 lines of code we'll demonstrate how EKS Pods can use AWS IAM to create
fine-grained permissions for apps that integrate with other AWS services.
* [Pod Access Control](#pod-access-control)
* [Create an OIDC provider](#create-an-oidc-provider)
* [Create IAM for a S3 app](#create-iam-for-a-s3-app)
* [Deploy a S3 app](#deploy-a-s3-app)
* [Wrap-Up](#wrap-up)
* [Next Steps](#next-steps)
## Pod Access Control
AWS EKS supports using IAM entities in a Pod [Service Account][k8s-sa] by
leveraging an [OIDC provider][aws-oidc] connected to the Kubernetes cluster.
Continuing with the example from the [AWS blog post][aws-pod-iam], when an [S3 app written in Go][s3-app] pushes
an object to a bucket with the AWS SDK, it will need write access to S3.
When a Pod is launched with a particular Service Account, the OIDC provider works
with Kubernetes to verify the Pod's identity, and in turn collaborates with the
[AWS Secure Token Service (STS)][aws-sts] to grant the Pod temporary
credentials to use with the IAM role.
## Create an OIDC provider
Creating an OIDC provider is as simple as toggling the `createOidcProvider` option
in the definition of your EKS cluster.
When enabled, the OIDC provider will be created and associated with the
cluster's OIDC provider URL.
```typescript
import * as eks from '@pulumi/eks'
// Create an EKS cluster with default settings.
// Create and attach an OIDC provider to the cluster.
const cluster = new eks.Cluster('myCluster', {
createOidcProvider: true,
});
```
## Create IAM for a S3 app
We'll use the OIDC provider URL and Amazon Resource Name (ARN) to compose the
[AssumeRoleWithWebIdentity][aws-assume-role-web], and S3 IAM policies that will
be attached to a new S3 IAM role.
After the role is configured, a Service Account for the S3 Pod will be
created, and annotated with the ARN of the S3 role to bind the two together.
```typescript
import * as aws from '@pulumi/aws'
import * as k8s from '@pulumi/kubernetes'
import * as pulumi from '@pulumi/pulumi'
// Create a pulumi Kubernetes provider using the cluster's kubeconfig.
const k8sProvider = new k8s.Provider('k8s', {
kubeconfig: cluster.kubeconfig.apply(JSON.stringify),
});
// Create a k8s namespace in the cluster.
const namespace = new k8s.core.v1.Namespace('apps', undefined, { k8sProvider });
// Get the OIDC provider's URL for the cluster.
const clusterOidcProvider = cluster.core.oidcProvider.url;
// Create the new IAM policy for the Service Account using the AssumeRoleWebWebIdentity action.
const saName = 's3'
const saAssumeRolePolicy = pulumi
.all([clusterOidcProviderUrl, clusterOidcProvider.arn, appsNamespaceName])
.apply(([url, arn, namespace]) =>
aws.iam.getPolicyDocument({
statements: [
{
actions: ['sts:AssumeRoleWithWebIdentity'],
conditions: [
{
test: 'StringEquals',
values: [`system:serviceaccount:${namespace.metadata.name}:${saName}`],
variable: `${url.replace('https://', '')}:sub`,
},
],
effect: 'Allow',
principals: [{identifiers: [arn], type: 'Federated'}],
},
],
})
);
// Create a new IAM role that assumes the AssumeRoleWebWebIdentity policy.
const saRole = new aws.iam.Role(saName, {
assumeRolePolicy: saAssumeRolePolicy.json,
});
// Attach the IAM role to an AWS S3 access policy.
const saS3Rpa = new aws.iam.RolePolicyAttachment(saName, {
policyArn: 'arn:aws:iam::aws:policy/AmazonS3FullAccess',
role: saRole,
});
// Create a Service Account with the IAM role annotated to use with the Pod.
const sa = new k8s.core.v1.ServiceAccount(
saName,
{
metadata: {
namespace: namespace.metadata.name,
name: saName,
annotations: {
'eks.amazonaws.com/role-arn': saRole.arn,
},
},
},
{ k8sProvider });
```
## Deploy a S3 app
We'll deploy the [S3 app][peks-oidc] to use the new IAM-backed Service Account.
Once the Pod is running, the Service Account annotation will be automatically
managed by a [Kubernetes dynamic admission controller][k8s-dynamic-webhook] run
by EKS on your behalf.
The [AWS EKS webhook][eks-webhook] manages Pod identity, and injects STS
credentials into the Pod to use with the S3 role.
With the credentials, the app can successfully upload data to S3.
```typescript
import * as aws from "@pulumi/aws";
import * as k8s from "@pulumi/kubernetes";
import * as pulumi from "@pulumi/pulumi";
const bucket = new aws.s3.Bucket("pod-irsa-job-bucket");
const bucketName = bucket.id;
const regionName = pulumi.output(aws.getRegion({}, {async: true})).name;
const s3Pod = new k8s.core.v1.Pod(podName,
{
metadata: {labels: labels, namespace: appsNamespaceName},
spec: {
serviceAccountName: sa.metadata.name,
containers: [
{
name: podName,
image: "amazonlinux:2018.03",
command: ["sh", "-c",
pulumi.interpolate`curl -sL -o /s3-echoer https://git.io/JfnGX && chmod +x /s3-echoer && echo This is an in-cluster test | /s3-echoer ${bucketName} && sleep 3600`,
],
env: [
{name: "AWS_DEFAULT_REGION", value: regionName},
{name: "ENABLE_IRP", value: "true"},
],
},
],
},
}, { provider: provider },
);
```
## Wrap-Up
Leveraging AWS IAM for Pod workloads is a secure and effective means of limiting
privileged execution, and provides a native experience for users.
Pod IAM can be extended further by also using the Kubernetes RBAC system. This
allows configuring permissions for Kubernetes API resources, and handle scenarios
such as limiting the namespace an IAM role can use, and what resources can be
managed in the namespace.
## Next Steps
Learn more about how [Pulumi works with Kubernetes][pulumi-k8s], and [get started][p-get-started]
if you're new.
Check out code examples for the S3 app referenced in this post,
along with other access control scenarios for EKS.
* [S3 app: EKS and an OIDC provider for Pod IAM.][peks-oidc]
* [Create an EKS cluster with Kubernetes RBAC for a Developer scoped IAM role.][peks-scoped-kubeconfigs]
* [More EKS examples][eks-examples]
Watch the video below for more details on how OIDC and Kubernetes RBAC works in
EKS. We demonstrate how to deploy [fluentd-cloudwatch][fluentd-cloudwatch] with
IAM to forward Pod logs to [AWS CloudWatch][aws-cw].
You can also follow us on [Twitter](https://twitter.com/pulumicorp),
subscribe to [PulumiTV](https://www.youtube.com/channel/UC2Dhyn4Ev52YSbcpfnfP0Mw) on YouTube,
or join our [Community Slack](https://slack.pulumi.com/) channel if you have any questions.
{{< youtube "7qN9ABgmK9M" >}}
[peks-oidc]: https://github.com/pulumi/pulumi-eks/tree/master/examples/oidc-iam-sa
[peks-scoped-kubeconfigs]: https://github.com/pulumi/pulumi-eks/tree/master/examples/scoped-kubeconfigs
[fluentd-cloudwatch]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs.html
[aws-cw]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html
[aws-eks]: https://aws.amazon.com/eks/
[aws-iam]: https://aws.amazon.com/iam/
[aws-pod-iam]: https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/
[aws-oidc]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html
[s3-app]: https://github.com/mhausenblas/s3-echoer
[aws-sts]: https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html
[eks-examples]: https://github.com/pulumi/pulumi-eks/tree/master/examples
[aws-assume-role-web]: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html
[k8s-dynamic-webhook]: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers
[eks-webhook]: https://github.com/aws/amazon-eks-pod-identity-webhook/
[k8s-sa]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
[pulumi-k8s]: /registry/packages/kubernetes/
[p-get-started]: /docs/clouds/kubernetes/get-started/