From 18bd032b3e7ecffac5b0dc40da6bfd34cae05af9 Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Fri, 17 Jul 2020 16:49:40 -0400 Subject: [PATCH 01/10] initial pass at s3 buckets and IAM role --- defaults/main.yml | 8 ++ tasks/aws_s3.yml | 104 +++++++++++++++++++++ templates/s3/AssetManagementPolicy.json.j2 | 25 +++++ templates/s3/TrustPolicy.json.j2 | 17 ++++ 4 files changed, 154 insertions(+) create mode 100644 tasks/aws_s3.yml create mode 100644 templates/s3/AssetManagementPolicy.json.j2 create mode 100644 templates/s3/TrustPolicy.json.j2 diff --git a/defaults/main.yml b/defaults/main.yml index 0d09307..271a0a2 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -144,6 +144,14 @@ k8s_collectstatic_command: - -v - "2" +k8s_s3_cluster_name: "" +k8s_s3_region: "us-east-1" +k8s_s3_namespace: "{{ k8s_namespace }}" +k8s_s3_iam_role: "S3ServiceAccountRole-{{ k8s_s3_namespace }}" +k8s_s3_serviceaccount: "default" +k8s_s3_public_bucket: "{{ k8s_s3_namespace }}-assets" +k8s_s3_private_bucket: "{{ k8s_s3_namespace }}-private-assets" + k8s_templates: - name: registry_secret.yaml.j2 state: "{{ k8s_dockerconfigjson | ternary('present', 'absent') }}" diff --git a/tasks/aws_s3.yml b/tasks/aws_s3.yml new file mode 100644 index 0000000..173d446 --- /dev/null +++ b/tasks/aws_s3.yml @@ -0,0 +1,104 @@ +--- + +# +# Public S3 assets bucket +# + +- name: "create public bucket {{ k8s_s3_public_bucket }}" + s3_bucket: + name: "{{ k8s_s3_public_bucket }}" + state: present + versioning: yes + region: "{{ k8s_s3_region }}" + +# +# Private S3 assets bucket +# + +- name: "create private bucket {{ k8s_s3_private_bucket }}" + s3_bucket: + name: "{{ k8s_s3_private_bucket }}" + state: present + versioning: yes + region: "{{ k8s_s3_region }}" + encryption: AES256 + +# Not available via Ansible module as of 7/2020 +- name: "block all public access to {{ k8s_s3_private_bucket }}" + command: + argv: + - aws + - s3api + - put-public-access-block + - --bucket + - "{{ k8s_s3_private_bucket }}" + - --public-access-block-configuration + - BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=false + +# +# IAM OIDC identity provider and issuer +# + +# https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html +- name: create an IAM OIDC identity provider for the cluster + command: "eksctl utils associate-iam-oidc-provider --cluster {{ k8s_s3_cluster_name }} --approve" + register: associate_response + changed_when: "'created' in associate_response.stdout" + +# Not available via Ansible module as of 7/2020 +- name: describe cluster to obtain OIDC issuer + command: "aws eks describe-cluster --region {{ k8s_s3_region }} --name {{ k8s_s3_cluster_name }} --output json" + changed_when: false + register: cluster_query + +- name: parse OIDC issuer from response + set_fact: + oidc_issuer: "{{ cluster_query.stdout | from_json | json_query('cluster.identity.oidc.issuer') | regex_replace('https://') }}" + +# +# AWS Account ID +# + +- name: get the current caller identity information + aws_caller_info: + register: caller_info + +- name: parse AWS account ID + set_fact: + aws_account_id: "{{ caller_info.account }}" + +# +# IAM Role +# + +# https://docs.aws.amazon.com/eks/latest/userguide/create-service-account-iam-policy-and-role.html +- name: Create IAM role for K8s service account + iam_role: + name: "{{ k8s_s3_iam_role }}" + assume_role_policy_document: "{{ lookup('template', 's3/TrustPolicy.json.j2') }}" + description: IAM role for K8s service account + +- name: Attach inline policy to user + iam_policy: + iam_type: role + iam_name: "{{ k8s_s3_iam_role }}" + policy_name: "EKSBucketPolicy" + state: present + policy_json: "{{ lookup( 'template', 's3/AssetManagementPolicy.json.j2') }}" + +# +# Service Account +# + +# https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html +- name: "Associate IAM role with the service account in your cluster" + k8s: + state: present + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: "{{ k8s_s3_serviceaccount }}" + namespace: "{{ k8s_s3_namespace }}" + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam::{{ aws_account_id }}:role/{{ k8s_s3_iam_role }}" diff --git a/templates/s3/AssetManagementPolicy.json.j2 b/templates/s3/AssetManagementPolicy.json.j2 new file mode 100644 index 0000000..e524f58 --- /dev/null +++ b/templates/s3/AssetManagementPolicy.json.j2 @@ -0,0 +1,25 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:ListBucket" + ], + "Resource": [ + "arn:aws:s3:::{{ k8s_s3_public_bucket }}", + "arn:aws:s3:::{{ k8s_s3_private_bucket }}", + ] + }, + { + "Effect": "Allow", + "Action": [ + "s3:*" + ], + "Resource": [ + "arn:aws:s3:::{{ k8s_s3_public_bucket }}/*", + "arn:aws:s3:::{{ k8s_s3_private_bucket }}/*" + ] + } + ] +} diff --git a/templates/s3/TrustPolicy.json.j2 b/templates/s3/TrustPolicy.json.j2 new file mode 100644 index 0000000..d819cf2 --- /dev/null +++ b/templates/s3/TrustPolicy.json.j2 @@ -0,0 +1,17 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::{{ aws_account_id }}:oidc-provider/{{ oidc_issuer }}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "{{ oidc_issuer }}:sub": "system:serviceaccount:{{ k8s_s3_namespace }}:{{ k8s_s3_serviceaccount }}" + } + } + } + ] +} From 2d468c8ccb75629e136485a337cbd76816d12178 Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Fri, 17 Jul 2020 16:54:43 -0400 Subject: [PATCH 02/10] add section to README --- README.rst | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/README.rst b/README.rst index 191b1a0..6e43651 100644 --- a/README.rst +++ b/README.rst @@ -139,3 +139,45 @@ Celery k8s_worker_image_pull_policy: "{{ k8s_container_image_pull_policy }}" k8s_worker_image_tag: "{{ k8s_container_image_tag }}" k8s_worker_resources: "{{ k8s_container_resources }}" + + +Amazon S3: IAM role for service accounts +```````````````````````````````````````` + +Django applications running on AWS typically use Amazon S3 for static and media +resources. ``caktus.django-k8s`` optionally supports enabling a Kubernetes +service account and associated IAM role that defines the access to public and +private S3 buckets. This provides similar functionality of +`EC2 instance profiles `_ +within Kubernetes namespaces. This +`AWS blog post `_ +also provides a good overview. + +At a high level, the process is: + +1. Create public and private S3 buckets +2. `Enable IAM roles for cluster service accounts `_ + * Requirement: `eksctl `_ must be installed +3. `Create an IAM role with a trust relatinoship and S3 policy for a service account `_ +4. `Annotate the service account with the ARN of the IAM role `_ + +Required variables: + + * ``k8s_s3_cluster_name``: name of EKS cluster in AWS + +A separate playbook can be used to invoke this functionality: + +.. code-block:: yaml + + --- + # file: s3.yaml + + - hosts: k8s + vars: + ansible_connection: local + ansible_python_interpreter: "{{ ansible_playbook_python }}" + tasks: + - name: configure Amazon S3 buckets + import_role: + name: caktus.django-k8s + tasks_from: aws_s3 From 7c8f5671cdcab4c670d7deb3cc8c5458185a02a6 Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Fri, 17 Jul 2020 18:01:00 -0400 Subject: [PATCH 03/10] add comment to k8s_s3_cluster_name --- defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defaults/main.yml b/defaults/main.yml index 271a0a2..4bad9a4 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -144,7 +144,7 @@ k8s_collectstatic_command: - -v - "2" -k8s_s3_cluster_name: "" +k8s_s3_cluster_name: "" # name of EKS cluster in AWS k8s_s3_region: "us-east-1" k8s_s3_namespace: "{{ k8s_namespace }}" k8s_s3_iam_role: "S3ServiceAccountRole-{{ k8s_s3_namespace }}" From 1b88c4442cb5a4e86f4a894a376c9b7230ddc8dd Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Fri, 17 Jul 2020 18:01:08 -0400 Subject: [PATCH 04/10] enable RestrictPublicBuckets --- tasks/aws_s3.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/aws_s3.yml b/tasks/aws_s3.yml index 173d446..46e5746 100644 --- a/tasks/aws_s3.yml +++ b/tasks/aws_s3.yml @@ -33,7 +33,7 @@ - --bucket - "{{ k8s_s3_private_bucket }}" - --public-access-block-configuration - - BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=false + - BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true # # IAM OIDC identity provider and issuer From 65b1b7c36d38a540aefdbb162fe02bcd66f7be7f Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Fri, 17 Jul 2020 18:11:43 -0400 Subject: [PATCH 05/10] add note about dropping eksctl requirement --- tasks/aws_s3.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/aws_s3.yml b/tasks/aws_s3.yml index 46e5746..b60b18e 100644 --- a/tasks/aws_s3.yml +++ b/tasks/aws_s3.yml @@ -40,6 +40,9 @@ # # https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html +# Possibly replace in future with (to remove eksctl requirement): +# 1. https://docs.aws.amazon.com/cli/latest/reference/iam/create-open-id-connect-provider.html +# 2. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html - name: create an IAM OIDC identity provider for the cluster command: "eksctl utils associate-iam-oidc-provider --cluster {{ k8s_s3_cluster_name }} --approve" register: associate_response From d3b11ec0e0a42e9c2b4910207cfa2a69f017e80a Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Fri, 17 Jul 2020 18:16:44 -0400 Subject: [PATCH 06/10] update name of playbook --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6e43651..91ac9ca 100644 --- a/README.rst +++ b/README.rst @@ -170,7 +170,7 @@ A separate playbook can be used to invoke this functionality: .. code-block:: yaml --- - # file: s3.yaml + # file: deploy-s3.yaml - hosts: k8s vars: @@ -181,3 +181,5 @@ A separate playbook can be used to invoke this functionality: import_role: name: caktus.django-k8s tasks_from: aws_s3 + +Run with: ``ansible-playbook deploy-s3.yml``. From e12aaf0164d760df9709a1a0e2c1c86fdba74898 Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Sat, 18 Jul 2020 22:32:22 -0400 Subject: [PATCH 07/10] allow access to /var/run/secrets/eks.amazonaws.com/serviceaccount/ --- templates/web.yaml.j2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/web.yaml.j2 b/templates/web.yaml.j2 index 5c2ad89..00a616f 100644 --- a/templates/web.yaml.j2 +++ b/templates/web.yaml.j2 @@ -49,7 +49,8 @@ spec: ports: - containerPort: {{ container["port"] }} resources: {{ container["resources"] | to_json }} - securityContext: {} + securityContext: + fsGroup: 2000 --- apiVersion: v1 kind: Service From 800b89906b088bb6efe2bf6e690cc999e270d0ca Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Tue, 28 Jul 2020 16:38:48 -0400 Subject: [PATCH 08/10] add gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..61017f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +.python-version From d73b8b49cfea4949a6e05f6c83d57f2c62f7feb4 Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Tue, 28 Jul 2020 16:39:58 -0400 Subject: [PATCH 09/10] refer to web applications --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 91ac9ca..f1e8618 100644 --- a/README.rst +++ b/README.rst @@ -144,7 +144,7 @@ Celery Amazon S3: IAM role for service accounts ```````````````````````````````````````` -Django applications running on AWS typically use Amazon S3 for static and media +Web applications running on AWS typically use Amazon S3 for static and media resources. ``caktus.django-k8s`` optionally supports enabling a Kubernetes service account and associated IAM role that defines the access to public and private S3 buckets. This provides similar functionality of From 88614e693bc1ac2e6014aa39a815fc19ee687199 Mon Sep 17 00:00:00 2001 From: Colin Copeland Date: Tue, 28 Jul 2020 16:40:07 -0400 Subject: [PATCH 10/10] remove trailing comma --- templates/s3/AssetManagementPolicy.json.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/s3/AssetManagementPolicy.json.j2 b/templates/s3/AssetManagementPolicy.json.j2 index e524f58..574107b 100644 --- a/templates/s3/AssetManagementPolicy.json.j2 +++ b/templates/s3/AssetManagementPolicy.json.j2 @@ -8,7 +8,7 @@ ], "Resource": [ "arn:aws:s3:::{{ k8s_s3_public_bucket }}", - "arn:aws:s3:::{{ k8s_s3_private_bucket }}", + "arn:aws:s3:::{{ k8s_s3_private_bucket }}" ] }, {