Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DP-505 Add production to the pipeline, tidy code and docs #766

Merged
merged 2 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 20 additions & 205 deletions terragrunt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,209 +2,24 @@

This code base is responsible for provisioning the AWS infrastructure needed to support the CDP SIRSI application.

## Table of Contents
1. [Bootstrap New Account](#bootstrap-a-new-account)
2. [Create New User](#create-new-users)
3. [Manage Secrets](#manage-secrets)
- [Retrieve Diagnostic URI](#Retrieve-iagnostic-uri)
- [Update Companies House Secrets](#update-companies-house-secrets)
- [Update FtsService URL](#update-ftsservice-url)
- [Update GOVUKNotify ApiKey](#update-govuknotify-apikey)
- [Update GOVUKNotify Support Admin Email](#update-govuknotify-support-admin-email)
- [Update OneLogin Secrets](#update-onelogin-secrets)
- [Update Slack Configuration](#update-slack-configuration)
4. [Pin Service Version](#pin-service-version)

## Bootstrap a new account

### Initiate

**TL;DR:**
```shell
# ave is alias for `aws-vault exec` command
# aws-switch-to-* is alias to set the:
# - AWS_PROFILE
# - TG_ENVIRONMENT
# - AWS_ENV (Not compulsory)
# - MFA_TOKEN handler (Out of scope of this documentation)

./tools/delete_tf_cache.sh
cd components/core/iam
aws-switch-to-cdp-sirsi-staging-bootstrap
ave terragrunt apply
aws-switch-to-cdp-sirsi-staging-terraform
ave aws sts get-caller-identity | cat
```

**Summary:**
- Ensure the cache is cleared.
- Navigate to the `core/iam` component.
- Assume the account bootstrap role.
- Set the `TG_ENVIRONMENT` environment variable (staging in the following example).
- Apply Terraform using Terragrunt while the bootstrap role is assumed.
- When Terragrunt prompts for the creation of the state bucket, allow it to be created.\
![bootstrap-start.png](../docs/images/infra/bootstrap-start.png)
- Core IAM will create the Terraform role to be used from now on.\
![bootstrap-output-terraform-role.png](../docs/images/infra/bootstrap-output-terraform-role.png)
- Assume the Terraform role.
- Confirm the caller identity.\
![bootstrao-confirm-terraform-caller.png](../docs/images/infra/bootstrao-confirm-terraform-caller.png)

### Provision rest of the components
- Navigate to the root directory
- Create the OneLogin secret `cdp-sirsi-one-login-credentials`, i.e:
```shell
ave aws secretsmanager create-secret --name cdp-sirsi-one-login-credentials --secret-string '{"Authority":"https://stagingoidc.example.com", "ClientId": "staging-client-id", "PrivateKey":"DEV RSA PRIVATE KEY"}'
```
- Create the Authority secret `cdp-sirsi-authority-key`, i.e:
```shell
make generate-authority-keys
ave make aws-push-authority-keys
```
- Navigate to the root of components
- Apply all, while terraform role is assumed
![terragrunt-apply-all](../docs/images/infra/terragrunt-apply-all.png)

- Build and push images to ECR
```shell
ave make aws-push-to-ecr
```

---

## Create new users

We are using Cognito user pools to restrict access to non-production accounts. The [cognito_create_user.sh](./tools/scripts/cognito_create_user.sh) script allows us to create new users with a randomly generated password.

```shell
# To create a user called DP-405
./tools/scripts/cognito_create_user.sh DP-405
```
The credentials will also be stored in AWS Secrets Manager under the same account, within the cdp-sirsi-cognito/users/* namespace, for future use, such as sharing with third-party users.

---

## Manage Secrets

### Retrieve Diagnostic URI

1. Set your AWS profile to target the specified AWS account, and use the AWS CLI to retrieve the full URL of the diagnostic page for the given account.

```shell
# ave is alias for `aws-vault exec` command
echo "https://$(ave aws route53 list-hosted-zones --query 'HostedZones[0].Name' --output text | sed 's/\.$//')$(ave aws secretsmanager get-secret-value --secret-id cdp-sirsi-diagnostic-path --query 'SecretString' --output text)"
```

### Update Companies House Secrets

1. Create a JSON file in the `./secrets` folder with the following attributes, e.g., **companies-house-secrets-development.json**:

```json
{
"url": "https://api.company-information.service.gov.uk",
"User": "<value>",
"Password": "<value>"
}
```
Note: The `./secrets` folder is set to ignore all files to ensure no sensitive information is committed.

2. Assume the appropriate role for the target environment and update the secret:

```shell
# ave is alias for `aws-vault exec` command
# add using:
# ave aws secretsmanager create-secret --name cdp-sirsi-companies-house-credentials --secret-string file://secrets/companies-house-secrets-development.json | jq .
# or update using:
ave aws secretsmanager put-secret-value --secret-id cdp-sirsi-companies-house-credentials --secret-string file://secrets/companies-house-secrets-development.json | jq .
```
3. Redeploy the `organisation-app` service.

### Update FtsService URL

1. Identify the `FTS service URL` for the specified AWS account.
2. Set your AWS profile to target the specified AWS account, and use the AWS CLI to update the secret.
> **Note:** In this documentation, `ave` is an alias for the `aws-vault exec` command, and `aws-switch-to-*` is an alias that configures the following:
> - `AWS_PROFILE`
> - `TG_ENVIRONMENT`
> - `AWS_ENV` (optional)
> - `MFA_TOKEN` handler (out of scope for this documentation)
>
> You are welcome to use any profile manager or tool you are more comfortable with.

```shell
# ave is alias for `aws-vault exec` command
# add using:
# ave aws secretsmanager create-secret --name cdp-sirsi-fts-service-url --secret-string "<FTS service URL>" | jq .
# or update using:
ave aws secretsmanager put-secret-value --secret-id cdp-sirsi-fts-service-url --secret-string "<FTS service URL>" | jq .
```

3. Redeploy the `organisation-app` service.

### Update GOVUKNotify ApiKey

1. Identify the `GOV UK Notify API Key` for the specified AWS account.
2. Set your AWS profile to target the specified AWS account, and use the AWS CLI to update the secret.

```shell
# ave is alias for `aws-vault exec` command
# add using:
# ave aws secretsmanager create-secret --name cdp-sirsi-govuknotify-apikey --secret-string "<GOV UK Notify API Key>" | jq .
# or update using:
ave aws secretsmanager put-secret-value --secret-id cdp-sirsi-govuknotify-apikey --secret-string "<GOV UK Notify API Key>" | jq .
```

3. Redeploy the `organisation` service.

### Update GOVUKNotify Support Admin Email

_this is a temporary solution while we are managing such user in the database_
1. Identify the `GOV UK Notify Support Admin Email` for the specified AWS account.
2. Set your AWS profile to target the specified AWS account, and use the AWS CLI to update the secret.

```shell
# ave is alias for `aws-vault exec` command
# add using:
# ave aws secretsmanager create-secret --name cdp-sirsi-govuknotify-support-admin-email --secret-string "<GOV UK Notify API Key>" | jq .
# or update using:
ave aws secretsmanager put-secret-value --secret-id cdp-sirsi-govuknotify-support-admin-email --secret-string "<GOV UK Notify API Key>" | jq .
```

3. Redeploy the `organisation` service.

### Update OneLogin secrets

1. Create a JSON file in the `./secrets` folder with the following attributes, e.g., **onelogin-secrets-development.json**:

```json
{
"Authority":"https://xxxxx",
"ClientId": "xxxxx",
"PrivateKey":"-----BEGIN RSA PRIVATE KEY-----\nxxxx\nxxxx==\n-----END RSA PRIVATE KEY-----%"
}
```
Note: The `./secrets` folder is set to ignore all files to ensure no sensitive information is committed.

2. Assume the appropriate role for the target environment and update the secret:

```shell
# ave is alias for `aws-vault exec` command
# add using:
# ave aws secretsmanager create-secret --name cdp-sirsi-one-login-credentials --secret-string file://secrets/onelogin-secrets-development.json | jq .
# or update using:
ave aws secretsmanager put-secret-value --secret-id cdp-sirsi-one-login-credentials --secret-string file://secrets/onelogin-secrets-development.json | jq .
```
3. Redeploy the `organisation-app` service.

### Update Slack Configuration

When the orchestrator's notification component is enabled, the system will notify a specified Slack channel about important CI/CD events. The required configuration for this connection must be stored as a secret named slack-configuration in the Orchestrator account. To create this secret, add a file named slack-notification-api-endpoint.txt under the secrets directory, containing a single line with the Slack API endpoint. Then, run the following command.

```shell
aws-switch-to-cdp-sirsi-orchestrator-goaco-terraform
ave aws secretsmanager create-secret --name cdp-sirsi-slack-api-endpoint --name cdp-sirsi-fts-service-url --secret-string file://secrets/slack-notification-api-endpoint.txt | jq .

```

This command will create a secret named cdp-sirsi-slack-api-endpoint in AWS Secrets Manager, setting its value from the contents of the slack-notification-api-endpoint.txt file in the secrets' directory.

---

## Pin Service Version

To pin services to a specific version in the given account, we can set the pinned_service_version in the [main configuration file](./components/terragrunt.hcl). If this value is left null, the system will default to using the latest published version, as specified in the service-version parameter within the Orchestrator account's SSM.

![pin-service-version](../docs/images/infra/pin-service-version.png)
## Table of Contents
- [Bootstrap New Account](./docs/bootstap-new-account.md)
- [Create New User](./docs/bootstap-new-account.md#create-new-users)
- [Manage Secrets](./docs/manage-secrets.md)
- [Retrieve Diagnostic URI](./docs/manage-secrets.md#retrieve-diagnostic-uri)
- [Update Companies House Secrets](./docs/manage-secrets.md#update-companies-house-secrets)
- [Update FtsService URL](./docs/manage-secrets.md#update-ftsservice-url)
- [Update GOVUKNotify ApiKey](./docs/manage-secrets.md#update-govuknotify-apikey)
- [Update GOVUKNotify Support Admin Email](./docs/manage-secrets.md#update-govuknotify-support-admin-email)
- [Update OneLogin Secrets](./docs/manage-secrets.md#update-onelogin-secrets)
- [Update Slack Configuration](./docs/manage-secrets.md#update-slack-configuration)
- [Pin Application/Service Version](./docs/bootstap-new-account.md#pin-applicationservice-version)
- [Run Databases' Migrations](./docs/bootstap-new-account.md#run-databases-migrations)
141 changes: 141 additions & 0 deletions terragrunt/docs/bootstap-new-account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Bootstrap a New Account

> **Note:** In this documentation, `ave` is an alias for the `aws-vault exec` command, and `aws-switch-to-*` is an alias that configures the following:
> - `AWS_PROFILE`
> - `TG_ENVIRONMENT`
> - `AWS_ENV` (optional)
> - `MFA_TOKEN` handler (out of scope for this documentation)
>
> You are welcome to use any profile manager or tool you are more comfortable with.

## Table of Contents
1. [Add New Account to the Global Configuration](#add-new-account-to-the-global-configuration)
2. [Initiate](#initiate)
3. [Provision Rest of the Components](#provision-rest-of-the-components)
1. [Create/Update Secrets](#createupdate-secrets)
2. [Create New Users](#create-new-users)
3. [Apply Terraform Across All Components](#apply-terraform-across-all-components)
4. [Run Databases' Migrations](#run-databases-migrations)
4. [Pin Application/Service Version](#pin-applicationservice-version)
5. [Add Deployment Stage(s) To The Pipeline]


---

## Add New Account to the Global Configuration

Before proceeding, ensure that the new account is properly configured by adding it to the global configuration file. You’ll need to define all required attributes under a new section in the [components/terragrunt.hcl](../components/terragrunt.hcl) file, within the `environments` block.

To do this, simply copy the configuration of an existing environment (account) and adjust the values for the new account as needed. Attributes to update include the `account_id`, `name`, `cidr_block`, subnets, and other environment-specific values.

### Example Configuration:

```hcl
environments = {
new_account_name = {
cidr_block = "10.${local.cidr_b_new_account}.0.0/16"
account_id = <new_account_id>
name = "new_account_name"
postgres_instance_type = "db.t4g.micro"
private_subnets = [
"10.${local.cidr_b_new_account}.101.0/24",
"10.${local.cidr_b_new_account}.102.0/24",
"10.${local.cidr_b_new_account}.103.0/24"
]
public_subnets = [
"10.${local.cidr_b_new_account}.1.0/24",
"10.${local.cidr_b_new_account}.2.0/24",
"10.${local.cidr_b_new_account}.3.0/24"
]
top_level_domain = "<new_account_domain>"
}
}
```

This ensures the new account is fully integrated into the configuration and is ready for subsequent steps like deployment.

## Initiate

Before provisioning the other components, it is essential to ensure that the basic requirements, especially IAM entities, are in place. Without these, provisioning will fail due to insufficient permissions. To address this, we first need to assume the admin/bootstrap role and provision the project-specific IAM roles required to continue.

Later on, using a similar process but assuming the Terraform role created in this step, we will provision all other components.

**TL;DR:**
```shell
./tools/delete_tf_cache.sh
cd components/core/iam
aws-switch-to-cdp-sirsi-staging-bootstrap
ave terragrunt apply
aws-switch-to-cdp-sirsi-staging-terraform
ave aws sts get-caller-identity | cat
```

**Summary:**
- Ensure the cache is cleared.
- Navigate to the `core/iam` component.
- Assume the account bootstrap role.
- Set the `TG_ENVIRONMENT` environment variable (e.g., staging).
- Apply Terraform using Terragrunt while the bootstrap role is assumed.
- When Terragrunt prompts to create the state bucket, allow it.\
![bootstrap-start.png](./images/bootstrap-start.png)
- The Core IAM component will create the Terraform role for future use.\
![bootstrap-output-terraform-role.png](./images/bootstrap-output-terraform-role.png)
- Assume the Terraform role.
- Confirm the caller identity.\
![bootstrap-confirm-terraform-caller.png](./images/bootstrap-confirm-terraform-caller.png)

## Provision Rest of the Components

### Create/Update Secrets

Ensure all required secrets for the target environment are in place by following the [manage-secrets.md](./manage-secrets.md) instructions.

> **Note**: Some secrets belong to the Orchestrator account only.

### Apply Terraform Across All Components
1. Navigate to the components folder.
2. Apply all components while assuming the **corresponding account's Terraform role**.
![terragrunt-apply-all](./images/terragrunt-apply-all.png)

### Run Databases' Migrations

```shell
# Fetch the AWS Account ID and set the region
export ACCOUNT_ID=$(ave aws sts get-caller-identity --query 'Account' --output text)
export SF_REGION=eu-west-2

# Execute the second Step Function: cdp-sirsi-run-organisation-information-migrations
ave aws stepfunctions start-execution \
--state-machine-arn arn:aws:states:${SF_REGION}:${ACCOUNT_ID}:stateMachine:cdp-sirsi-run-organisation-information-migrations \
--name "organisation-information-execution-$(date +%Y%m%d%H%M%S)" \
--input '{}'

# Execute the first Step Function: cdp-sirsi-run-entity-verification-migrations
ave aws stepfunctions start-execution \
--state-machine-arn arn:aws:states:${SF_REGION}:${ACCOUNT_ID}:stateMachine:cdp-sirsi-run-entity-verification-migrations \
--name "entity-verification-execution-$(date +%Y%m%d%H%M%S)" \
--input '{}'


```
### Create New Users

We use Cognito user pools to restrict access to **non-production accounts**. The [cognito_create_user.sh](./tools/scripts/cognito_create_user.sh) script allows us to create new users with randomly generated passwords.

```shell
# To create a user called DP-405
./tools/scripts/cognito_create_user.sh <username>
```

The credentials will also be stored in AWS Secrets Manager under the same account, within the `cdp-sirsi-cognito/users/*` namespace, for future use, such as sharing with third-party users.

## Pin Application/Service Version

To pin services to a specific version in the account, set the `pinned_service_version` in the [main configuration file](../components/terragrunt.hcl). If this value is left null, the system defaults to using the latest published version, as specified in the service-version parameter within the Orchestrator account's SSM.

![pin-service-version](images/pin-service-version.png)


## Add Deployment Stage(s) to the Pipeline

Finally, extend the [deployment pipeline](../modules/orchestrator/ci/pipeline.tf) to include automated deployment to the new account.
File renamed without changes.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added terragrunt/docs/images/bootstrap-start.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added terragrunt/docs/images/pin-service-version.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added terragrunt/docs/images/terragrunt-apply-all.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading