From 128fb9950c1354c211abe17d5cba19d75dd66ecc Mon Sep 17 00:00:00 2001
From: Eytan Dahan <eytan@captain-eye.com>
Date: Fri, 8 Nov 2024 20:28:23 +0000
Subject: [PATCH] feat: add AWS CodeArtifact support (variant)

---
 README.md                                     | 69 +++++++++++++++++++
 kicker.json                                   | 55 +++++++++++++++
 .../gitlab-ci-python-aws-codeartifact.yml     | 60 ++++++++++++++++
 3 files changed, 184 insertions(+)
 create mode 100644 templates/gitlab-ci-python-aws-codeartifact.yml

diff --git a/README.md b/README.md
index 4af1d89..325ff9b 100644
--- a/README.md
+++ b/README.md
@@ -575,3 +575,72 @@ include:
       gcp-oidc-provider: "projects/<gcp_nonprod_proj_id>/locations/global/workloadIdentityPools/<pool_id>/providers/<provider_id>"
       gcp-oidc-account: "<name>@$<gcp_nonprod_proj_id>.iam.gserviceaccount.com"
 ```
+
+### AWS CodeArtifact variant
+
+This variant allows to use PyPi packages from AWS CodeArtifact. The variant follow the recommendation [Authenticate for using client libraries](https://docs.aws.amazon.com/codeartifact/latest/ug/python-configure.html) 
+
+It authenticates with AWS CodeArtifact, retrieves and sets the following environment variable:
+
+- `CODEARTIFACT_AUTH_TOKEN` - the AWS CodeArtifact authentication token
+- `CODEARTIFACT_REPOSITORY_ENDPOINT` - the AWS CodeArtifact repository endpoint
+- `CODEARTIFACT_URL` - Formatted URL for the AWS CodeArtifact repository
+
+Most importantly, the variant sets the `pip global.index-url` to the CodeArtifact url.
+
+The variant supports two authentication methods:
+
+1. [federated authentication using OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/aws/) (**recommended method**),
+2. or basic authentication with AWS access key ID & secret access key.
+
+:warning: when using this variant, you must have created the CodeArtifact repository.
+
+#### Configuration
+
+The variant *requires* the additional configuration parameters:
+
+| Input / Variable                              | Description                                                                                                           | Default value                                                         |
+| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
+| `TBC_AWS_PROVIDER_IMAGE`                      | The [AWS Auth Provider](https://gitlab.com/to-be-continuous/tools/aws-auth-provider) image to use (can be overridden) | `registry.gitlab.com/to-be-continuous/tools/aws-auth-provider:latest` |
+| `aws-region` / `AWS_REGION`                   | Default region (where the Codeartifact repository is located)                                                         | _none_                                                                |
+| `aws-codeartifact-domain` / `AWS_CODEARTIFACT_DOMAIN` | The CodeArtifact domain name                                                                                       | _none_                                                                |
+| `aws-codeartifact-domain-owner` / `AWS_CODEARTIFACT_DOMAIN_OWNER` | The CodeArtifact domain owner account ID                                                                      | _none_                                                                |
+| `aws-codeartifact-repository` / `AWS_CODEARTIFACT_REPOSITORY` | The CodeArtifact repository name                                                                                 | _none_                                                                |
+
+##### OIDC authentication config
+
+This is the recommended authentication method. In order to use it, first carefuly follow [GitLab's documentation](https://docs.gitlab.com/ee/ci/cloud_services/aws/),
+then set the required configuration.
+
+| Input / Variable                                            | Description                                                                                    | Default value    |
+| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------- |
+| `aws-oidc-aud` / `AWS_OIDC_AUD`                             | The `aud` claim for the JWT token                                                              | `$CI_SERVER_URL` |
+| `aws-oidc-role-arn` / `AWS_OIDC_ROLE_ARN`                   | Default IAM Role ARN associated with GitLab                                                    | _none_           |
+
+##### Basic authentication config
+
+| Variable                                | Description                                                                  | Default value     |
+| --------------------------------------- | ---------------------------------------------------------------------------- | ----------------- |
+| :lock: `AWS_ACCESS_KEY_ID`              | Default access key ID                                                        | _none_ (disabled) |
+| :lock: `AWS_SECRET_ACCESS_KEY`          | Default secret access key                                                    | _none_ (disabled) |
+
+
+#### Example
+
+```yaml
+include:
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python@7.3.2
+    # 2: set/override component inputs
+    inputs:
+      image: registry.hub.docker.com/library/python:3.12-slim
+      pytest-enabled: true
+
+  - component: $CI_SERVER_FQDN/to-be-continuous/python/gitlab-ci-python-aws-ca@7.3.2
+    inputs:
+      aws-region: "us-east-1"
+      aws-codeartifact-domain: "acme"
+      aws-codeartifact-domain-owner: "123456789012"
+      aws-codeartifact-repository: "my-repo"
+      # common OIDC config for non-prod envs
+      aws-oidc-role-arn: "arn:aws:iam::123456789012:role/gitlab-ci"
+```
\ No newline at end of file
diff --git a/kicker.json b/kicker.json
index c6110d1..4f55200 100644
--- a/kicker.json
+++ b/kicker.json
@@ -348,6 +348,61 @@
           "description": "Default Workload Identity Provider associated with GitLab to [authenticate with OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/google_cloud/)"
         }
       ]
+    },
+    {
+      "id": "aws-codeartifact",
+      "name": "AWS CodeArtifact",
+      "description": "Retrieves AWS CodeArtifact credentials",
+      "template_path": "templates/gitlab-ci-python-aws-codeartifact.yml",
+      "variables": [
+        {
+          "name": "TBC_AWS_PROVIDER_IMAGE",
+          "description": "The [AWS Auth Provider](https://gitlab.com/to-be-continuous/tools/aws-auth-provider) image to use",
+          "default": "registry.gitlab.com/to-be-continuous/tools/aws-auth-provider:latest",
+          "advanced": true
+        },
+        {
+          "name": "AWS_REGION",
+          "description": "Default region (where the codeartifact repository is located)"
+        },
+        {
+          "name": "AWS_OIDC_AUD",
+          "description": "The `aud` claim for the JWT token _(only required for [OIDC authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_",
+          "default": "$CI_SERVER_URL",
+          "advanced": true
+        },
+        {
+          "name": "AWS_OIDC_ROLE_ARN",
+          "description": "Default IAM Role ARN associated with GitLab _(only required for [OIDC authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_"
+        },
+        {
+          "name": "AWS_ACCESS_KEY_ID",
+          "description": "Default access key ID (only required for basic authentication)",
+          "secret": true,
+          "advanced": true
+        },
+        {
+          "name": "AWS_SECRET_ACCESS_KEY",
+          "description": "Default secret access key (only required for basic authentication)",
+          "secret": true,
+          "advanced": true
+        },
+        {
+          "name": "AWS_CODEARTIFACT_DOMAIN",
+          "description": "The AWS CodeArtifact domain",
+          "mandatory": true
+        },
+        {
+          "name": "AWS_CODEARTIFACT_DOMAIN_OWNER",
+          "description": "The AWS CodeArtifact domain owner",
+          "mandatory": true
+        },
+        {
+          "name": "AWS_CODEARTIFACT_REPOSITORY",
+          "description": "The AWS CodeArtifact repository",
+          "mandatory": true
+        }
+      ]
     }
   ]
 }
diff --git a/templates/gitlab-ci-python-aws-codeartifact.yml b/templates/gitlab-ci-python-aws-codeartifact.yml
new file mode 100644
index 0000000..f95fd93
--- /dev/null
+++ b/templates/gitlab-ci-python-aws-codeartifact.yml
@@ -0,0 +1,60 @@
+# =====================================================================================================================
+# === AWS CodeArtifact Auth template variant
+# =====================================================================================================================
+spec:
+  inputs:
+    aws-codeartifact-domain:
+      description: AWS CodeArtifact domain name
+      default: ''
+    aws-codeartifact-domain-owner:
+      description: AWS CodeArtifact domain owner account ID
+      default: ''
+    aws-codeartifact-repository:
+      description: AWS CodeArtifact repository name
+      default: ''
+    aws-region:
+      description: Default region (where the Codeartifact registry is located)
+      default: ''
+    aws-oidc-aud:
+      description: The `aud` claim for the JWT token _(only required for [OIDC authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_
+      default: $CI_SERVER_URL
+    aws-oidc-role-arn:
+      description: Default IAM Role ARN associated with GitLab _(only required for [OIDC
+        authentication](https://docs.gitlab.com/ee/ci/cloud_services/aws/))_
+      default: ''
+---
+variables:
+  TBC_AWS_PROVIDER_IMAGE: registry.gitlab.com/to-be-continuous/tools/aws-auth-provider:latest
+  AWS_OIDC_AUD: $[[ inputs.aws-oidc-aud ]]
+  AWS_REGION: $[[ inputs.aws-region ]]
+  AWS_OIDC_ROLE_ARN: $[[ inputs.aws-oidc-role-arn ]]
+  AWS_CODEARTIFACT_DOMAIN: $[[ inputs.aws-codeartifact-domain ]]
+  AWS_CODEARTIFACT_DOMAIN_OWNER: $[[ inputs.aws-codeartifact-domain-owner ]]
+  AWS_CODEARTIFACT_REPOSITORY: $[[ inputs.aws-codeartifact-repository ]]
+
+
+.codeartifact-pip-config:
+  before_script:
+    - CODEARTIFACT_URL=https://aws:${CODEARTIFACT_AUTH_TOKEN}@${CODEARTIFACT_REPOSITORY_ENDPOINT#https://}simple
+    - pip config set global.index-url $CODEARTIFACT_URL
+
+.python-base:
+  services:
+    - name: "$TBC_TRACKING_IMAGE"
+      command: ["--service", "python", "7.3.0"]
+    - name: "$TBC_AWS_PROVIDER_IMAGE"
+      alias: "aws-auth-provider"
+  id_tokens:
+    # required for OIDC auth
+    AWS_JWT:
+      aud: "$AWS_OIDC_AUD"
+  variables:
+    CODEARTIFACT_AUTH_TOKEN: "@url@http://aws-auth-provider/codeartifact/auth/token"
+    CODEARTIFACT_REPOSITORY_ENDPOINT: "@url@http://aws-auth-provider/codeartifact/repository/endpoint?format=pypi"
+    AWS_JWT: "$AWS_JWT"
+  before_script:
+    - !reference [.codeartifact-pip-config:]
+    - !reference [.python-scripts]
+    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
+    - cd ${PYTHON_PROJECT_DIR}
+    - guess_build_system
-- 
GitLab