Commit 823ea7ef authored by Thomas Boni's avatar Thomas Boni
Browse files

Merge branch '518-new-job-deploy-s3-terraform' into 'latest'

Resolve "[New Job] - Deploy S3 Terraform"

Closes #518

See merge request r2devops/hub!364
parents 916575d6 c47a4fb3
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
# Changelog
All notable changes to this job will be documented in this file.

## [0.1.0] - 2022-06-10
* Initial version
 No newline at end of file
+167 −0
Original line number Diff line number Diff line
## Objective

Deploy a static website on a S3 bucket provided by a Terraform state. It is a fusion of [gitlab-terraform_apply](https://r2devops.io/_/r2devops-bot/gitlab-terraform_apply) and  [aws_s3_sync](https://r2devops.io/_/r2devops-bot/aws_s3_sync).

## How to use it

1. Make sure that you have your terraform files in your repository and update the `TF_ROOT` variable to point to the folder containing your terraform files.
1. Set your Terraform secret variables in the `Gitlab CI/CD` variables section of your project (see the [Terraform documentation](https://www.terraform.io/docs/configuration/variables.html){:target="_blank"} about variables) .

    !!! info "Terraform HTTP Backend"
    By default, this job will run using the `http` backend, so you have to follow the [instructions](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html#initialize-a-terraform-state-as-a-backend-by-using-gitlab-cicd){:target="_blank"} to configure it in advance.
1. Set your AWS credentials variables in the `Gitlab CI/CD` variables section of your project (see the [S3 documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html){:target="_blank"} about credentials) .

    ??? summary "Need a custom Endpoint ⚓ ?"
      Just type your custom url in the variable `AWS_ENDPOINT`.  
      For example, you can find the custom endpoint url for Scaleway [here](https://www.scaleway.com/en/docs/storage/object/api-cli/object-storage-aws-cli/){:target="_blank"}.

    ??? info "Set up a bucket policy 👮"
      Depending on your Cloud provider, you might need to set up a bucket policy. You can specify it via the variable `AWS_BUCKET_POLICY_FILE`. For example, you can find some documentation for bucket policy for Amazon S3 [here](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-policy-language-overview.html){:target="_blank"}.
1. Make sure to fulfill all mandatory variables. See the **Variables** section 👇
1. Copy the job URL located in the `Install` part of the right panel and add it inside the `include` list of your `.gitlab-ci.yml` file (see the [quick setup](/use-the-hub/#quick-setup)). You can specify [a fixed version](#changelog) instead of `latest`.
1. If you need to customize the job (stage, variables, ...) 👉 check the [jobs
   customization](/use-the-hub/#jobs-customization)
1. Well done, your job is ready to work ! 😀

## Job details

* Job name: `deploy_s3_terraform`
* Docker image:
[`registry.gitlab.com/gitlab-org/terraform-images/releases/1.2:v0.40.0`](https://gitlab.com/gitlab-org/terraform-images/container_registry/3083041)
* Default stage: `deploy`
* When: `always`

### Variables

!!! warning 
    Some variable are required to let the job work. Many of them are *secrets*, they should be define in the `CI/CD > Variables` section in [GitLab](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project) to avoid exposing them in clear in your `.gitlab-ci.yml`. This is **HIGHLY** recommended for sensitive credential variables such as cloud providers tokens and passwords.

| Name | Description | Required | Secrets | Default |
| ---- | ----------- | -------- | ------- | ------- |
| `AWS_ACCESS_KEY_ID` <img width=100/> | Access key <img width=175/> | ✅ <img width=100/> | ✅ <img width=100/> | ` ` <img width=100/> |
| `AWS_SECRET_ACCESS_KEY` | Secret key | ✅ | ✅ | ` ` |
| `AWS_DEFAULT_REGION` | Region used | ✅ | ❌ | `eu-west-1` |
| `AWS_BUCKET_NAME` | Name of the S3 bucket | ✅ | ❌ | ` ` |
| `AWS_ENDPOINT` | Custom endpoint if needed | ❌ | ❌ | ` ` |
| `AWS_ACL` | If you want to add an ACL (e.g. `public-read`) | ❌ | ❌ | ` ` |
| `AWS_SYNC_DIR` | Region used | ✅ | ❌ | `build` |
| `AWS_DELETE_OLD_FILE` | Delete previous files in the S3 bucket | ✅ | ❌ | `true` |
| `AWS_BUCKET_POLICY_FILE` | Policy applied to the S3 bucket (`json` format) | ❌ | ❌ | ` ` |
| `AWS_DEPLOY_WEBSITE` | Deploy a static website from `AWS_SYNC_DIR` root directory | ✅ | ❌ | `true` |
| `TF_WEBSITE_HOMEPAGE` | The home page of your website | ✅ | ❌ | `index.html` |
| `TF_WEBSITE_ERRORPAGE` | The error page of your website | ✅ | ❌ | `error.html` |
| `AWS_CLI_VERSION` | The version of the AWS console | ✅ | ❌ | `2.7.7` |
| `TF_ADDRESS` | Address to terraform state backend | ✅ | ❌ | `${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/main` |
| `TF_ROOT` | The root directory for Terraform | ✅ | ❌ | `terraform` |

### Configuring Terraform

To works well with Terraform, variable should be defined in the `CI/CD > Variables` section in [GitLab](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project).


### Here is an working example of deploying a website on a S3 bucket hosted by Scaleway

Structure : 
```sh
build/ #Directory where the website is built
terraform/
├─ main.tf
├─ backend.tf
├─ variables.tf

```

`main.tf`
```tf
terraform {
  required_providers {
    scaleway = {
      source = "scaleway/scaleway"
    }
  }
  required_version = ">= 0.13"
}

provider "scaleway" {
  access_key = var.SCW_ACCESS_KEY
  secret_key = var.SCW_SECRET_KEY
  project_id = var.project_id
  region     = var.region
}

resource "scaleway_object_bucket" "bucket_website" {
  name = var.bucket_name
  acl  = var.acl
  versioning {
    enabled = var.enabled_bucket_versioning
  }
  lifecycle {
    prevent_destroy = true
  }

}

```

Concerning the variables, you can find the [scaleway](https://docs.gitlab.com/ee/ci/variables/#scaleway-variables) variables in the [GitLab CI/CD > Variables](https://docs.gitlab.com/ee/ci/variables/) section.

![CI/CD variables on GitLab](./screenshots/ci_cd_variables.png)

And here is the file where there are defined `variables.tf` :

```tf
variable "SCW_ACCESS_KEY" {
  type        = string
  description = "Scaleway secret access key"
}

variable "SCW_SECRET_KEY" {
  type        = string
  description = "Scaleway secret id key"
}

variable "project_id" {
  type        = string
  description = "Scaleway Organisation or project id used"
}

variable "bucket_name" {
  type        = string
  description = "Name of the s3 bucket"
}

variable "region" {
  type        = string
  description = "Region where is hosted the bucket"
}

variable "enabled_bucket_versioning" {
  type        = bool
  default     = false
  description = "Should the buket be versionned"
}

variable "acl" {
  type        = string
  description = "Bucket visibility"
}

```
Finally here is the content of the `backend.tf` file :

```tf
terraform {
  # Gitlab managed terraform state
  backend "http" {
  }
}

```

For more information here are some useful links :
- [Setting up static websites on a bucket with the Scaleway API](https://www.scaleway.com/en/docs/storage/object/api-cli/bucket-website-api/)
- [Deploying Your First Infrastructure on Scaleway using Terraform](https://www.scaleway.com/en/docs/tutorials/terraform-quickstart/)

**Documentation 📕**
- [Terraform with Scaleway](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs)
- [Bucket policy](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html)
+99 −0
Original line number Diff line number Diff line
stages:
  - deploy

cache:
  key:
    files:
    - "${CI_PROJECT_DIR}/${TF_ROOT}/.terraform.lock.hcl"
  paths:
    - "${CI_PROJECT_DIR}/${TF_ROOT}/.terraform"

deploy_s3_terraform:
  image: registry.gitlab.com/gitlab-org/terraform-images/releases/1.2:v0.40.0
  stage: deploy
  variables: 
    AWS_ACCESS_KEY_ID: ""
    AWS_SECRET_ACCESS_KEY: ""
    AWS_DEFAULT_REGION: "eu-west-1"
    AWS_BUCKET_NAME: ""
    AWS_ENDPOINT: ""
    AWS_ACL: ""
    AWS_SYNC_DIR: "website_build"
    AWS_DELETE_OLD_FILE: "true"
    AWS_BUCKET_POLICY_FILE: ""
    AWS_DEPLOY_WEBSITE: "true"
    AWS_WEBSITE_HOMEPAGE: "index.html"
    AWS_WEBSITE_ERRORPAGE: "error.html"
    AWS_CLI_VERSION: "2.7.7"
    TF_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/main"
    TF_ROOT: "${CI_PROJECT_DIR}/terraform"

  script:
    - |
      apk --no-cache add \
        curl \
        && GLIBC_VER="2.34-r0" \
      && curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
      && curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk \
      && curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk \
      && apk add --no-cache --force-overwrite \
        glibc-${GLIBC_VER}.apk \
        glibc-bin-${GLIBC_VER}.apk \
        unzip \
      && wget -O awscliv2.zip https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip \
      && unzip -qq awscliv2.zip \
      && aws/install

    # Checking and Applying terraform state
    - export TF_VAR_website_homepage=${AWS_WEBSITE_HOMEPAGE} TF_VAR_website_errorpage=${AWS_WEBSITE_ERRORPAGE}
    - cd ${TF_ROOT}
    - if terraform fmt -check -diff ${TF_ROOT}; then
    -   echo "Terraform files are OK"
    - else
    -   echo "Terraform files are not OK. you should launch \`terraform fmt\` to fix them"
    -   exit 1
    - fi
    - gitlab-terraform init | tee output.log
    - gitlab-terraform validate | tee -a output.log
    - gitlab-terraform plan | tee -a output.log
    - gitlab-terraform plan-json | tee -a output.log
    - mkdir ${TF_ROOT}_def
    - "(cd ${TF_ROOT}; tar cvf - .) | (cd ${TF_ROOT}_def; tar xvf -)"
    - gitlab-terraform apply

    # Set Endpoint URL
    - cd ${CI_PROJECT_DIR}
    - ENDPOINT_URL=""
    - if [ ! -z ${AWS_ENDPOINT} ]; then
    -   ENDPOINT_URL="--endpoint-url ${AWS_ENDPOINT}"
    - fi

    # Deploying website
    - if [ ${AWS_DEPLOY_WEBSITE} == "true" ]; then
    -   aws s3 website s3://${TF_VAR_bucket_name}/ --index-document ${AWS_WEBSITE_HOMEPAGE} \
        --error-document ${AWS_WEBSITE_ERRORPAGE} ${ENDPOINT_URL}
    - fi

    # Configuring policy and substitute variables
    - if [ -n ${AWS_BUCKET_POLICY_FILE} ]; then
    -   apk update && apk add gettext
    -   cat ${AWS_BUCKET_POLICY_FILE} > tmp_bucket_policy.json
    -   envsubst < tmp_bucket_policy.json > bucket-policy.json
    -   aws s3api put-bucket-policy --bucket ${TF_VAR_bucket_name} --policy file://bucket-policy.json ${ENDPOINT_URL}
    - fi

    # Syncing website
    - AWS_OPTIONS="${ENDPOINT_URL}"
    - $([ ! -z ${AWS_ACL} ]) && AWS_OPTIONS="${AWS_OPTIONS} --acl ${AWS_ACL}"
    - $([ ${AWS_DELETE_OLD_FILE} == "true" ]) && AWS_OPTIONS="${AWS_OPTIONS} --delete"
    - aws s3 sync ${AWS_SYNC_DIR} s3://${TF_VAR_bucket_name}/ ${AWS_OPTIONS}
    
  artifacts:
    when: always
    expose_as: "Terraform artifact"
    paths:
      - "${TF_ROOT}/output.log"
      - "${TF_ROOT}/plan.cache"
      - "${TF_ROOT}_def"
    reports:
      terraform: "${TF_ROOT}/plan.json"
 No newline at end of file
+0 −0

Empty file added.

+84.2 KiB
Loading image diff...