Commit a277eab4 authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

doc: reorganise the chapters

parent 6c73375a
Loading
Loading
Loading
Loading
+123 −118
Original line number Diff line number Diff line
# GitLab CI template for Amazon Web Services

This project implements a generic GitLab CI template for [Amazon Web Services](https://aws.amazon.com/) environments.
This project implements a generic GitLab CI template to deploy to [Amazon Web Services](https://aws.amazon.com/).

## Overview: managed environments
## Usage

In order to include this template in your project, add the following to your `gitlab-ci.yml`:

```yaml
include:
  - project: 'to-be-continuous/aws'
    ref: '2.2.0'
    file: '/templates/gitlab-ci-aws.yml'
```

## Understand

This chapter introduces key notions and principle to understand how this template works.

### Managed deployment environments

This template implements continuous delivery/continuous deployment for projects hosted on AWS.

@@ -13,7 +28,7 @@ workflow, by reusing/extending the base (hidden) jobs. This is advanced usage an

The following chapters present the managed predefined environments and their associated Git workflow.

### Review environments
#### Review environments

The template supports **review** environments: those are dynamic and ephemeral environments to deploy your
_ongoing developments_ (a.k.a. _feature_ or _topic_ branches).
@@ -25,7 +40,7 @@ It is a strict equivalent of GitLab's [Review Apps](https://docs.gitlab.com/ee/c

It also comes with a _cleanup_ job (accessible either from the _environments_ page, or from the pipeline view).

### Integration environment
#### Integration environment

If you're using a Git Workflow with an integration branch (such as [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)),
the template supports an **integration** environment.
@@ -33,7 +48,7 @@ the template supports an **integration** environment.
When enabled, it deploys the result from upstream build stages to a dedicated environment.
It is only active for your integration branch (`develop` by default).

### Production environments
#### Production environments

Lastly, the template supports 2 environments associated to your production branch (`master` or `main` by default):

@@ -45,89 +60,65 @@ You're free to enable whichever or both, and you can also choose your deployment
* **continuous deployment**: automatic deployment to production (when the upstream pipeline is successful),
* **continuous delivery**: deployment to production can be triggered manually (when the upstream pipeline is successful).

## Usage

### Include
### Supported authentication methods

In order to include this template in your project, add the following to your `gitlab-ci.yml`:

```yaml
include:
  - project: 'to-be-continuous/aws'
    ref: '2.2.0'
    file: '/templates/gitlab-ci-aws.yml'
```

### Global configuration
The AWS template supports two kinds of authentication:

The AWS template uses some global configuration used throughout all jobs.
1. basic authentication with AWS access key ID & secret access key,
2. or [federated authentication using OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/aws/).

| Name                     | description                            | default value     |
| ------------------------ | -------------------------------------- | ----------------- |
| `AWS_CLI_IMAGE`          | the Docker image used to run AWS CLI commands| `amazon/aws-cli:latest` |
| `AWS_BASE_APP_NAME`      | Base application name                  | `$CI_PROJECT_NAME` ([see GitLab doc](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)) |
| `AWS_ENVIRONMENT_URL`    | Default environments url _(only define for static environment URLs declaration)_<br/>_supports late variable expansion (ex: `https://%{environment_name}.aws.acme.com`)_ | _none_ |
| `AWS_SCRIPTS_DIR`        | Directory where AWS scripts (deploy & cleanup) are located | `.` _(root project dir)_ |
| `AWS_OIDC_ROLE_ARN`    | Default IAM Role ARN associated with GitLab to [authenticate using OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/aws/) | _none_ (disabled) |
#### Basic authentication

### Secrets management
When using basic authentication (AWS access key ID & secret access key), this template **does not manage AWS authentication**.

Here are some advices about your **secrets** (variables marked with a :lock:): 
That means you'll have to manage AWS authentication by yourself, according to the `aws` CLI configuration options (configuration file, CLI options, environment variables).

1. Manage them as [project or group CI/CD variables](https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui):
    * [**masked**](https://docs.gitlab.com/ee/ci/variables/#mask-a-custom-variable) to prevent them from being inadvertently 
      displayed in your job logs,
    * [**protected**](https://docs.gitlab.com/ee/ci/variables/#protect-a-custom-variable) if you want to secure some secrets 
      you don't want everyone in the project to have access to (for instance production secrets).
2. In case a secret contains [characters that prevent it from being masked](https://docs.gitlab.com/ee/ci/variables/#masked-variable-requirements), 
  simply define its value as the [Base64](https://en.wikipedia.org/wiki/Base64) encoded value prefixed with `@b64@`: 
  it will then be possible to mask it and the template will automatically decode it prior to using it.
3. Don't forget to escape special characters (ex: `$` -> `$$`).
For credentials management, we strongly advise to use [environment variables configuration](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html#envvars-list), managed as GitLab CI secret variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, possibly `AWS_ROLE_ARN`).

### Deployment and cleanup scripts
If you have to manage different set of authentication credentials depending on managed environments, you shall either use [GitLab scoped variables](https://docs.gitlab.com/ee/ci/environments/index.html#scoping-environments-with-specs) or our [scoped variables syntax](https://to-be-continuous.gitlab.io/doc/usage/#scoped-variables) to limit/override some variables values, using `$CI_ENVIRONMENT_NAME` as the conditional variable.

The AWS template requires you to provide a shell script that fully implements your application
deployment and cleanup using the [`aws` CLI](https://aws.amazon.com/cli/) and all other tools available in the selected Docker image.
Example: different credentials for production (declared as project variables)

#### Lookup policy
```yaml
# global AWS credentials
AWS_ACCESS_KEY_ID: "<my-nonprod-access-key-id>"
AWS_SECRET_ACCESS_KEY: "<my-nonprod-secret-access-key>"

The deployment script is searched as follows:
# overridden configuration for production
scoped__AWS_ACCESS_KEY_ID__if__CI_ENVIRONMENT_NAME__equals__production: "<my-prod-access-key-id>"
scoped__AWS_SECRET_ACCESS_KEY__if__CI_ENVIRONMENT_NAME__equals__production: "<my-prod-secret-access-key>"
```

1. look for a specific `aws-deploy-$environment_type.sh` in the `$AWS_SCRIPTS_DIR` directory in your project (e.g. `aws-deploy-staging.sh` for staging environment),
2. if not found: look for a default `aws-deploy.sh` in the `$AWS_SCRIPTS_DIR` directory in your project,
3. if not found: the deployment job will fail.
#### Federated authentication using OpenID Connect

The cleanup script is searched as follows:
If you wish to use this authentication mode, please follow carefully [the GitLab guide](https://docs.gitlab.com/ee/ci/cloud_services/aws/), 
then configure appropriately the related variables:

1. look for a specific `aws-cleanup-$environment_type.sh` in the `$AWS_SCRIPTS_DIR` directory in your project (e.g. `aws-cleanup-staging.sh` for staging environment),
2. if not found: look for a default `aws-cleanup.sh` in the `$AWS_SCRIPTS_DIR` directory in your project,
3. if not found: the cleanup job will fail.
* `AWS_OIDC_ROLE_ARN` for any global/common access,
* `AWS_REVIEW_OIDC_ROLE_ARN` and/or `AWS_INTEG_OIDC_ROLE_ARN` and/or `AWS_STAGING_OIDC_ROLE_ARN` and/or `AWS_PROD_OIDC_ROLE_ARN` if you wish to use a separate role with any of your environments.

#### Dynamic Variables
### Deployment context variables

You have to be aware that your deployment (and cleanup) scripts have to be able to cope with various environments 
(`review`, `integration`, `staging` and `production`), each with different application names, exposed routes, settings, ...
In order to manage the various deployment environments, this template provides a couple of **dynamic variables**
that you might use in your hook scripts, deployment manifests and other deployment resources:

Part of this complexity can be handled by the lookup policies described above (ex: one resource per env).
* `${environment_type}`: the current deployment environment type (`review`, `integration`, `staging` or `production`)
* `${environment_name}`: a generated application name to use for the current deployment environment (ex: `myapp-review-fix-bug-12` or `myapp-staging`) - _details below_

In order to be able to implement some **genericity** in your scripts and templates, you should use available environment variables:
#### Generated environment name

1. any [GitLab CI variable](https://docs.gitlab.com/ee/ci/variables/#predefined-environment-variables)
    (ex: `${CI_ENVIRONMENT_URL}` to retrieve the actual environment exposed route) 
2. any [custom variable](https://docs.gitlab.com/ee/ci/variables/#custom-environment-variables)
    (ex: `${SECRET_TOKEN}` that you have set in your project CI/CD variables)
3. **dynamic variables** set by the template:
    * `${environment_type}`: the current environment type (`review`, `integration`, `staging` or `production`)
    * `${environment_name}`: the application name to use for the current environment (ex: `myproject-review-fix-bug-12` or `myproject-staging`) - see below
    * `${hostname}`: the environment hostname, extracted from the current environment url (after late variable expansion - see below)
The `${environment_name}` variable is generated to designate each deployment environment with a unique and meaningful application name.
By construction, it is suitable for inclusion in DNS, URLs, Kubernetes labels...
It is built from:

##### `environment_name` generation
* the application _base name_ (defaults to `$CI_PROJECT_NAME` but can be overridden globally and/or per deployment environment - _see configuration variables_)
* GitLab predefined `$CI_ENVIRONMENT_SLUG` variable ([sluggified](https://en.wikipedia.org/wiki/Clean_URL#Slug) name, truncated to 24 characters)

Each environment is given an _environment name_, generated programmatically by the template, using:
The `${environment_name}` variable is then evaluated as:

* `AWS_BASE_APP_NAME` defines the application _base_ name (defaults to `$CI_PROJECT_NAME`)
* `environment_name=$AWS_BASE_APP_NAME-$CI_ENVIRONMENT_SLUG` except for the production environment, where `environment_name` is directly `AWS_BASE_APP_NAME` (no suffix)
* each environment name can be overriden per environment with the appropriate `AWS_XXX_APP_NAME` variable
* `<app base name>` for the production environment
* `<app base name>-$CI_ENVIRONMENT_SLUG` for all other deployment environments
* :bulb: `${environment_name}` can also be overriden per environment with the appropriate configuration variable

Examples (with an application's base name `myapp`):

@@ -138,57 +129,49 @@ Examples (with an application's base name `myapp`):
| `staging`           | `main`        | `staging`               | `myapp-staging` |
| `production`        | `main`        | `production`            | `myapp` |

#### AWS authentication

The AWS template supports two kinds of authentication:

1. basic authentication with AWS access key ID & secret access key,
2. or [federated authentication using OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/aws/).

##### Basic authentication

When using basic authentication (AWS access key ID & secret access key), this template **does not manage AWS authentication**.

That means you'll have to manage AWS authentication by yourself, according to the `aws` CLI configuration options (configuration file, CLI options, environment variables).

For credentials management, we strongly advise to use [environment variables configuration](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html#envvars-list), managed as GitLab CI secret variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, possibly `AWS_ROLE_ARN`).

If you have to manage different set of authentication credentials depending on managed environments, you shall either use [GitLab scoped variables](https://docs.gitlab.com/ee/ci/environments/index.html#scoping-environments-with-specs) or our [scoped variables syntax](https://to-be-continuous.gitlab.io/doc/usage/#scoped-variables) to limit/override some variables values, using `$CI_ENVIRONMENT_NAME` as the conditional variable.
### Deployment and cleanup scripts

Example: different credentials for production (declared as project variables)
The AWS template requires you to provide a shell script that fully implements your application
deployment and cleanup using the [`aws` CLI](https://aws.amazon.com/cli/) and all other tools available in the selected Docker image.

```yaml
# global AWS credentials
AWS_ACCESS_KEY_ID: "<my-nonprod-access-key-id>"
AWS_SECRET_ACCESS_KEY: "<my-nonprod-secret-access-key>"
The deployment script is searched as follows:

# overridden configuration for production
scoped__AWS_ACCESS_KEY_ID__if__CI_ENVIRONMENT_NAME__equals__production: "<my-prod-access-key-id>"
scoped__AWS_SECRET_ACCESS_KEY__if__CI_ENVIRONMENT_NAME__equals__production: "<my-prod-secret-access-key>"
```
1. look for a specific `aws-deploy-$environment_type.sh` in the `$AWS_SCRIPTS_DIR` directory in your project (e.g. `aws-deploy-staging.sh` for staging environment),
2. if not found: look for a default `aws-deploy.sh` in the `$AWS_SCRIPTS_DIR` directory in your project,
3. if not found: the deployment job will fail.

##### Federated authentication using OpenID Connect
The cleanup script is searched as follows:

If you wish to use this authentication mode, please follow carefully [the GitLab guide](https://docs.gitlab.com/ee/ci/cloud_services/aws/), 
then configure appropriately the related variables:
1. look for a specific `aws-cleanup-$environment_type.sh` in the `$AWS_SCRIPTS_DIR` directory in your project (e.g. `aws-cleanup-staging.sh` for staging environment),
2. if not found: look for a default `aws-cleanup.sh` in the `$AWS_SCRIPTS_DIR` directory in your project,
3. if not found: the cleanup job will fail.

* `AWS_OIDC_ROLE_ARN` for any global/common access,
* `AWS_REVIEW_OIDC_ROLE_ARN` and/or `AWS_INTEG_OIDC_ROLE_ARN` and/or `AWS_STAGING_OIDC_ROLE_ARN` and/or `AWS_PROD_OIDC_ROLE_ARN` if you wish to use a separate role with any of your environments.
> :information_source: Your deployment (and cleanup) scripts have to be able to cope with various environments, each with different application names, exposed routes, settings, ...
> Part of this complexity can be handled by the lookup policies described above (ex: one script per env) and also by using available environment variables:
>
> 1. [deployment context variables](#deployment-context-variables) provided by the template:
>     * `${environment_type}`: the current environment type (`review`, `integration`, `staging` or `production`)
>     * `${environment_name}`: the application name to use for the current environment (ex: `myproject-review-fix-bug-12` or `myproject-staging`)
>     * `${hostname}`: the environment hostname, extracted from the current environment url (after late variable expansion - see below)
> 2. any [GitLab CI variable](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
> 3. any [custom variable](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project)
>     (ex: `${SECRET_TOKEN}` that you have set in your project CI/CD variables)

#### Static vs. Dynamic environment URLs
### Environments URL management

The AWS template supports two ways of defining your environments url:
The AWS template supports two ways of providing your environments url:

* a **static way**: when you know your environments url in advance, probably because you're exposing your routes through a DNS you manage,
* a **static way**: when the environments url can be determined in advance, probably because you're exposing your routes through a DNS you manage,
* a [**dynamic way**](https://docs.gitlab.com/ee/ci/environments/#set-dynamic-environment-urls-after-a-job-finishes): when the url cannot be known before the
  deployment job is executed.

The **static way** can be implemented simply by setting the appropriate configuration variable(s) depending on the environment (see environments configuration chapters below):
The **static way** can be implemented simply by setting the appropriate configuration variable(s) depending on the environment (see environments configuration chapters):

* `$AWS_ENVIRONMENT_URL` to define a default url pattern for all your envs,
* `$AWS_REVIEW_ENVIRONMENT_URL`, `$AWS_INTEG_ENVIRONMENT_URL`, `$AWS_STAGING_ENVIRONMENT_URL` and `$AWS_PROD_ENVIRONMENT_URL` to override the default.

> :information_source: Each of those variables support a late variable expansion mechanism with `%{somevar}` syntax, allowing you to use any dynamically evaluated variables such as `$environment_name`.
> :information_source: Each of those variables support a **late variable expansion mechanism** with the `%{somevar}` syntax, 
> allowing you to use any dynamically evaluated variables such as `${environment_name}`.
>
> Example:
>
@@ -197,30 +180,52 @@ The **static way** can be implemented simply by setting the appropriate configur
>   AWS_BASE_APP_NAME: "wonderapp"
>   # global url for all environments
>   AWS_ENVIRONMENT_URL: "https://%{environment_name}.nonprod.acme.domain"
>   # override for prod (no need to late exand $AWS_BASE_APP_NAME here)
>   # override for prod (late expansion of $AWS_BASE_APP_NAME not needed here)
>   AWS_PROD_ENVIRONMENT_URL: "https://$AWS_BASE_APP_NAME.acme.domain"
> ```

To implement the **dynamic way**, your deployment script shall simply generate a `environment_url.txt` file, containing only
the dynamically generated url.
To implement the **dynamic way**, your deployment script shall simply generate a `environment_url.txt` file in the working directory, containing only
the dynamically generated url. When detected by the template, it will use it as the newly deployed environment url.

#### Deployment output variables
### Deployment output variables

Each deployment job produces _output variables_ that are propagated to downstream jobs (using [dotenv artifacts](https://docs.gitlab.com/ee/ci/pipelines/job_artifacts.html#artifactsreportsdotenv)):

* `$environment_type`: set to the type of environment (`review`, `integration`, `staging` or `production`),
* `$environment_name`: the application name (see below),
* `$environment_url`: set to `$CI_ENVIRONMENT_URL`.
* `$environment_url`: set to the environment URL (whether determined statically or dynamically).

Those variables may be freely used in downstream jobs (for instance to run acceptance tests against the latest deployed environment).

### Environments configuration
## Configuration reference

As seen above, the AWS template may support up to 4 predefined environments (`review`, `integration`, `staging` and `production`).
### Secrets management

Here are configuration details for each environment.
Here are some advices about your **secrets** (variables marked with a :lock:): 

#### Review environments
1. Manage them as [project or group CI/CD variables](https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui):
    * [**masked**](https://docs.gitlab.com/ee/ci/variables/#mask-a-custom-variable) to prevent them from being inadvertently 
      displayed in your job logs,
    * [**protected**](https://docs.gitlab.com/ee/ci/variables/#protect-a-custom-variable) if you want to secure some secrets 
      you don't want everyone in the project to have access to (for instance production secrets).
2. In case a secret contains [characters that prevent it from being masked](https://docs.gitlab.com/ee/ci/variables/#masked-variable-requirements), 
  simply define its value as the [Base64](https://en.wikipedia.org/wiki/Base64) encoded value prefixed with `@b64@`: 
  it will then be possible to mask it and the template will automatically decode it prior to using it.
3. Don't forget to escape special characters (ex: `$` -> `$$`).

### Global configuration

The AWS template uses some global configuration used throughout all jobs and environments.

| Name                     | description                            | default value     |
| ------------------------ | -------------------------------------- | ----------------- |
| `AWS_CLI_IMAGE`          | the Docker image used to run AWS CLI commands| `amazon/aws-cli:latest` |
| `AWS_BASE_APP_NAME`      | Base application name                  | `$CI_PROJECT_NAME` ([see GitLab doc](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)) |
| `AWS_ENVIRONMENT_URL`    | Default environments url _(only define for static environment URLs declaration)_<br/>_supports late variable expansion (ex: `https://%{environment_name}.aws.acme.com`)_ | _none_ |
| `AWS_SCRIPTS_DIR`        | Directory where AWS scripts (deploy & cleanup) are located | `.` _(root project dir)_ |
| `AWS_OIDC_ROLE_ARN`    | Default IAM Role ARN associated with GitLab to [authenticate using OpenID Connect](https://docs.gitlab.com/ee/ci/cloud_services/aws/) | _none_ (disabled) |

### Review environments configuration

Review environments are dynamic and ephemeral environments to deploy your _ongoing developments_ (a.k.a. _feature_ or 
_topic_ branches).
@@ -236,7 +241,7 @@ Here are variables supported to configure review environments:
| `AWS_REVIEW_APP_NAME`    | Application name for `review` env      | `"${AWS_BASE_APP_NAME}-${CI_ENVIRONMENT_SLUG}"` (ex: `myproject-review-fix-bug-12`) |
| `AWS_REVIEW_ENVIRONMENT_URL`| The review environments url _(only define for static environment URLs declaration and if different from default)_ | `$AWS_ENVIRONMENT_URL` |

#### Integration environment
### Integration environment configuration

The integration environment is the environment associated to your integration branch (`develop` by default).

@@ -251,7 +256,7 @@ Here are variables supported to configure the integration environment:
| `AWS_INTEG_APP_NAME`     | Application name for `integration` env | `${AWS_BASE_APP_NAME}-integration` |
| `AWS_INTEG_ENVIRONMENT_URL`| The integration environment url _(only define for static environment URLs declaration and if different from default)_ | `$AWS_ENVIRONMENT_URL` |

#### Staging environment
### Staging environment configuration

The staging environment is an iso-prod environment meant for testing and validation purpose associated to your production 
branch (`master` by default).
@@ -267,7 +272,7 @@ Here are variables supported to configure the staging environment:
| `AWS_STAGING_APP_NAME`   | Application name for `staging` env     | `${AWS_BASE_APP_NAME}-staging` |
| `AWS_STAGING_ENVIRONMENT_URL`| The staging environment url _(only define for static environment URLs declaration and if different from default)_ | `$AWS_ENVIRONMENT_URL` |

#### Production environment
### Production environment configuration

The production environment is the final deployment environment associated with your production branch (`master` by default).

@@ -324,9 +329,9 @@ stages:

##### `aws-deploy.sh`

This script is executed by the template to perform the application(s) deployment based on `aws` CLI, and uses [dynamic variables](#dynamic-variables) provided by the template (`${environment_name}` is used as the CloudFormation stack name).
This script is executed by the template to perform the application(s) deployment based on `aws` CLI, and uses [deployment context variables](#deployment-context-variables) provided by the template (`${environment_name}` is used as the CloudFormation stack name).

It implements [dynamic environment URLs](#static-vs-dynamic-environment-urls), by generating the `environment_url.txt` file, containing
It implements [dynamic environment URLs](#environments-url-management), by generating the `environment_url.txt` file, containing
the dynamically generated url at the end of the deployment script.

```bash
@@ -426,9 +431,9 @@ stages:

##### `aws-deploy.sh`

This script is executed by the template to perform the application(s) deployment based on `sam`and `aws` CLI, and uses [dynamic variables](#dynamic-variables) provided by the template (`${environment_name}` is used as the SAM/CloudFormation stack name).
This script is executed by the template to perform the application(s) deployment based on `sam`and `aws` CLI, and uses [deployment context variables](#deployment-context-variables) provided by the template (`${environment_name}` is used as the SAM/CloudFormation stack name).

It implements [dynamic environment URLs](#static-vs-dynamic-environment-urls), by generating the `environment_url.txt` file, containing
It implements [dynamic environment URLs](#environments-url-management), by generating the `environment_url.txt` file, containing
the dynamically generated url at the end of the deployment script.

```bash