{"id":3774,"date":"2020-12-09T18:20:57","date_gmt":"2020-12-10T00:20:57","guid":{"rendered":"http:\/\/benincosa.com\/?p=3774"},"modified":"2020-12-09T23:56:19","modified_gmt":"2020-12-10T05:56:19","slug":"allowing-applications-in-aws-eks-to-access-other-aws-services","status":"publish","type":"post","link":"https:\/\/benincosa.com\/?p=3774","title":{"rendered":"Allowing Applications in AWS EKS to access other AWS services"},"content":{"rendered":"\n<p>I have an application that runs in a container.  The application is pretty simple in that all it does is list the contents of a DynamoDB database I created.  The code is <a href=\"https:\/\/github.com\/vallard\/EKS-Training\/tree\/master\/segment07-integrations\/dynamo-example\/app\">here<\/a>, as well as all the YAML files for deploying to EKS. The problem is, when we pull this up on a standard EKS cluster we get the following issue: <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"3110\" height=\"1150\" src=\"https:\/\/benincosa.com\/wp-content\/uploads\/2020\/12\/Screen-Shot-2020-12-09-at-9.42.16-AM.png\" alt=\"\" class=\"wp-image-3775\"\/><\/figure>\n\n\n\n<p>I&#8217;ve purposely allowed my application to display the AWS errors to the main screen so I could see that there is a permission issue.  The issue here is that the container is not authorized to access DynamoDB.  So we get IAM permission errors. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Quick and Easy Fix<\/h2>\n\n\n\n<p>The easy fix is to allow all the nodes in the cluster to access the DynamoDB resource.  When <code>eksctl<\/code> creates the managed nodes it also created an IAM role that is displayed in the error message: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>User: arn:aws:sts::188966951897:assumed-role\/eksctl-dec08-nodegroup-standard-w-NodeInstanceRole-1P18ZVF8HUQKY\/i-0d8b78cc00172b721 is not authorized to perform: dynamodb:Scan on resource: arn:aws:dynamodb:us-west-2:188966951897:table\/dynamoUsers<\/code><\/pre>\n\n\n\n<p>So we can go into IAM and add a new policy and then apply it to the <code>eksctl-dec08-nodegroup-standard-w-NodeInstanceRole-...<\/code> role.  This looks as follows: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"VisualEditor0\",\n            \"Effect\": \"Allow\",\n            \"Action\": \"dynamodb:Scan\",\n            \"Resource\": \"arn:aws:dynamodb:us-west-2:188966951897:table\/dynamoUsers\"\n        }\n    ]\n}<\/code><\/pre>\n\n\n\n<p>The problem with this approach is it now means that any container in the network can now access this database. We may decide that we only want certain pods to have the ability to access the database, and not leave it wide open. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">More Granularity: Pod Service Accounts<\/h2>\n\n\n\n<p>Let&#8217;s remove that policy from the node group and try a more secure way. Amazon supports <a href=\"https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/iam-roles-for-service-accounts-technical-overview.html\">IAM roles for service accounts<\/a> that can help us with this. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Add OpenID permissions to your EKS user<\/h3>\n\n\n\n<p>Back in IAM add the permission to the user (or group) to <code>iam:CreateOpenIDConnectProvider<\/code>.  This can be done as an inline policy or you could create a new policy.  You may also want to give them the permission to delete as well with <code>iam:DeleteOpenIDConnectProvider<\/code>. I&#8217;ve added it into an existing IAM policy, but at minimum it should look as follows: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": &#91;\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Action\": &#91;\n\n        \"iam:CreateOpenIDConnectProvider\",\n  \n      ],\n      \"Resources\" &#91;\n         \"arn:aws:iam::&lt;your account>:oidc-provider\/oidc.eks.&lt;yourregion>.amazonaws.com\",\n         \"arn:aws:iam::&lt;your account>:oidc-provider\/oidc.eks.&lt;yourregion>.amazonaws.com\/*\"\n    }\n  ]\n}<\/code><\/pre>\n\n\n\n<p>In other words, the user that created the EKS cluster should also have permissions to create an OpenIDConnectProvider on the cluster.  We accomplish this by adding the policy above.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Create OIDC Provider for the Cluster <\/h3>\n\n\n\n<p>Once the user has permission to do this run the following <code>eksctl<\/code> command to create the provider. You only need to do this once on the cluster.  <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ eksctl utils associate-iam-oidc-provider --cluster dec08 --approve\n[\u2139]  eksctl version 0.32.0\n[\u2139]  using region us-west-2\n[\u2139]  will create IAM Open ID Connect provider for cluster \"dec08\" in \"us-west-2\"\n[\u2714]  created IAM Open ID Connect provider for cluster \"dec08\" in \"us-west-2\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. Create Policy for Application<\/h3>\n\n\n\n<p>Next, decide what AWS resources your application will require access to and what the least amount of permissions they need.  In my case, my application only needs to Scan a particular DynamoDB table.  So I lock it down very tight and create a policy that allows that.  You can call the policy something like the applications name.  In mine, since its EKS accessing the DynamoDB Users table I called it <code>EKSDynamoUsers<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"VisualEditor0\",\n            \"Effect\": \"Allow\",\n            \"Action\": \"dynamodb:Scan\",\n            \"Resource\": \"arn:aws:dynamodb:us-west-2:188966951897:table\/dynamoUsers\"\n        }\n    ]\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">4. Create Service Account<\/h3>\n\n\n\n<p>Now that the OpenID is created and we have a policy, let&#8217;s create an IAM Service Account for EKS:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>eksctl create iamserviceaccount --name dynamo-users --namespace default --cluster dec08 --attach-policy-arn arn:aws:iam::188966951897:policy\/EKSDynamoUsers --approve --override-existing-serviceaccounts<\/code><\/pre>\n\n\n\n<p>The above command creates the Service Account named <code>dynamo-users<\/code> or something that should be unique for your application that the pod uses.  Once this is completed we should be able to see the service account in Kubernetes: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get serviceaccount<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5. Modify Pod To Use Service Account<\/h3>\n\n\n\n<p>Going back to our YAML file, we need to specify that the pod run with the service account we just created. To do this, we simply add the service account name to the YAML file.  This works well if the container is running as the root user: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: eks-dynamo\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      run: eks-dynamo\n  template:\n    metadata:\n      labels:\n        run: eks-dynamo\n    spec:\n      serviceAccountName: dynamo-users\n      containers:\n      - name: eks-dynamo\n        image: 188966951897.dkr.ecr.us-west-2.amazonaws.com\/vallard\/eks-dynamo:latest\n...<\/code><\/pre>\n\n\n\n<p>Notice that we add the <code>serviceAccount<\/code> to the container in the above code.  This will delete the current pod once we put <code>kubectl apply app.yaml<\/code> and the new one will run with the permissions. <\/p>\n\n\n\n<p>Now we can refresh and see that our application has access to perform the DynamoDB operation on that one table<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"900\" height=\"388\" src=\"http:\/\/benincosa.com\/wp-content\/uploads\/2020\/12\/Screen-Shot-2020-12-09-at-4.16.09-PM.png\" alt=\"\" class=\"wp-image-3778\"\/><figcaption>Example application running in EKS that accesses DynamoDB<\/figcaption><\/figure>\n\n\n\n<p>Hopefully that will help you if you have problems.  Check out my <a href=\"https:\/\/twitter.com\/vallard\">twitter<\/a> account if you have any questions. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have an application that runs in a container. The application is pretty simple in that all it does is list the contents of a DynamoDB database I created. The code is here, as well as all the YAML files for deploying to EKS. The problem is, when we pull this up on a standard&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[797],"tags":[958,962,961,960],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3774"}],"collection":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3774"}],"version-history":[{"count":7,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3774\/revisions"}],"predecessor-version":[{"id":3783,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3774\/revisions\/3783"}],"wp:attachment":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}