Dans mon article précédent, nous avons vu comment mettre en place un site web statique avec Hugo sur AWS via Terraform notamment celui qui héberge ce site.

Cela fait maintenant un peu plus d’un an (voire deux) que ce site est déployé de cette façon et j’ai eu l’occasion d’améliorer/changer plusieurs choses.

Dans cet article nous verrons les nouveautés apportées sur ce site notamment:

TL;TR: Pour ceux qui souhaitent déployer leurs infrastructures sur AWS avec la nouvelle version, voici le repository GitHub

Prérequis

Pour comprendre ce post, vous devez:

Pour reproduire l’exemple de ce blog, vous devez :

Rappel de l’infrastructure

Dans l’article précédent nous avons déployé l’infrastructure suivante: AWS CloudFront web static

Nous avons:

  • Amazon Route 53: Qui héberge notre Hosted Zone et notre domaine (mehdilaruelle.com)
  • Amazon CloudFront: Qui fait office de CDN (Content Delivry Network) et point d’entré pour nos end users
  • AWS Certificate Manager: Qui va héberger notre certificat et être utilisé par Amazon CloudFront pour le HTTPS
  • Un bucket S3: Qui hébergera notre site web statique déployé par Hugo et uniquement accessible par Amazon CloudFront. Notre bucket est donc privé

L’ensemble de l’infrastructure est déployé par Terraform.

Remplacement de l’OAI par l’OAC

Dans l’architecture que nous avons vue, le bucket S3 est privé et est uniquement accessible par Amazon CloudFront. Anciennement, la méthode utilisé était l’Origin Access Identity (OAI) qui est aujourd’hui déprécié. En guise de remplacement, AWS a mit en placce l’Origin Access Control (OAC).

Contrairement a l’OAI qui était vue comme un principal IAM CloudFront, ici l’OAC est vue comme une ressource AWS CloudFront. Les avantages de l’OAC par rapport à l’OAI sont le support de:

  • Tous les bucket S3 dans toutes les régions.
  • Chiffrement server-side encryption avec AWS KMS (SSE-KMS)
  • Requêtes dynamiques (PUT et DELETE) vers Amazon S3

Cette migration est plutôt simple car il suffit de:

  1. Créer un OAC
  2. Mettre la bucket policy
  3. Mettre à jour Amazon CloudFront en remplaçant l’OAI par l’OAC

Vous retrouverez le commit GitHub concernant cette migration ou encore la docummentation officiel d’AWS sur le sujet.

Upgrade du Terraform provider AWS v5

Ce n’est pas tous les jours que le provider AWS de Terraform reçoit une mise à jour majeur et c’est donc tout naturellement que l’upgrade s’imposait. Pour les plus curieux qui souhaite en savoir plus sur les nouveautés du provider, je vous invite a regarder le Upgrade Guide d’HashiCorp

Aucun impact au niveau du code Terraform mais je préfère explicitement l’indiquer au niveau du code Terraform:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>5.0"
    }
  }
}

Pour ceux qui ne connaisse pas, vous avez tfupdate utilisable via le pre-commit-terraform pour rester à jour sur vos dépendances.

Github action et credentials dynamique AWS

Jusqu’à peu, les déploiements de mes blog posts ou mise à jour des thèmes se faisait localement depuis mon terminal car ma fréquence de déploiement de mes blog posts était assez faible. Cependant, je faisais face à 2 problématiques:

  1. A chaque déploiement, je pouvais avoir des problèmes de résidus de cache ou encore d’autres anomalies liées a mon environnement
  2. Des credentials AWS statique qui étaient utilisés une fois tous les 3 mois au mieux. Plutôt dommage pour des credentials statique

Pour répondre à ces problématiques, j’ai:

  1. Mis en place GitHub Action (gratuit jusqu’à 2000 minutes par mois) pour automatiser le déploiement de mon site a chaque git push
  2. Mise en place de credential AWS temporaire a chaque déploiement dans GitHub action

Mise en place de GitHub Action

Mon objectif est: “A chaque push sur ma branche master, je veux que mon site Hugo soit déployé sur S3”. Bonne nouvelle, sur GitHub Action c’est possible de le faire (et gratuitement) assez facilement car il existe des Actions.

Dans un premier temps, j’ai utilisé l’Action Hugo de peaceiris pour l’usage de Hugo dans Github Action.

Voilà le contenu de mon fichier .github/workflows/main.yml de GitHub action:

name: Hugo deploy website on S3

on:
  push:
    branches: [ main ] # Only when a push is done on main branch

permissions:
      contents: read    # This is required for actions/checkout

jobs:
  Build_and_Deploy:
    runs-on: ubuntu-latest
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - name: Git clone the repository
      uses: actions/checkout@v4
      with:
        submodules: 'true' # Some Hugo theme are imported as a submodule, so you need it
    # Sets up Hugo with latest version
    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
          hugo-version: 'latest'
          extended: true
    - name: Build
      run: hugo --minify
    - name: Deploy to S3
      run: hugo deploy --force

Si nous résumons les étapes de notre job, nous avons:

  1. Checkout: Permet de cloner notre repository avec les submodules nécessaires pour les Hugo thèmes
  2. Setup Hugo: Installation de Hugo en édition extended. car certains de mes thèmes utilisent des fonctionnalités de cette éditio
  3. Build: On construit notre site web statique en version minify
  4. Deploy: Enfin, on déploie notre site web Hugo sur S3

Pour que Hugo sache comment déployer, au niveau de l’étape 4, il faudra ajouter la bonne configuration au niveau du config.toml. Dans mon cas, le bout de configuration ressemble à ça:

  [deployment]

  [[deployment.targets]]
    name = "aws"
    URL = "s3://hugo-website-mlaruelle?region=eu-west-3"

Remarque

L’URL doit contenir la region. La région dans mon cas est eu-west-3 (paris).

A ce stade, presque tout est fonctionnel. En effet, il nous manque les droits pour déployer sur le bucket S3.

Mise en place des credentials AWS temporaire

Jusqu’à présent, j’utilisais un IAM user avec des credentials statiques. Sachant que maintenant les déploiements se font via GitHub action, je me suis dit qu’il était temps de passer à des credentials temporaires afin d’avoir “des credentials à usage unique à chaque déploiement”.

Pour ce faire, j’ai utilisé un AWS Assume Role With Web Identity avec GitHub Action.

je vous invite à en apprendre plus sur l’ensemble du process et de la configuration via la documentation officielle de GitHub Action. Dans notre cas, nous allons résumer la migration vers cette méthode en 2 étapes:

  1. La mise en place de la Web Identity
  2. La mise en place du GitHub Action configure-aws-credentials-for-github-actions

Etape 1: Mise en place de la Web Identity

Cette première étape consiste à mettre en place un Identity Provider (de type OIDC) au niveau du service IAM et établir un lien de trust de IAM Identity Provider vers GitHub Action sur lequel GitHub Action pourra assumer notre rôle. En version simplifié, cela représente ça: IAM identity provider with GitHub

Pour ce faire, j’ai mis en place un Terraform pour mettre en place la Web Identity que j’invite les plus curieux a regarder.

Dans le repository Terraform, pour activer le déploiement de la Web Identity pour votre repository GibHub, vous devez fournir les valeurs aux variables github_org (le nom de l’organisation GitHub) et github_repositories (Une liste de repositories GitHub autorisé à assusmer la Web Identity role). Dans mon cas, cela donne ça:

github_org          = "mehdilaruelle" # GitHub Organization name
github_repositories = ["blog_hugo"] # The list of GitHub repositories to allow to assume the Web Identity role

Puis faites un terraform apply et récupérez l’output de aws_role_arn via un terraform output aws_role_arn. Gardez l’output, nous en aurons besoin pour la configuration de notre GitHub Action.

Etape 2: Mise en place du GitHub Action configure-aws-credentials-for-github-actions

Enfin, l’étape 2 consiste à ce que GitHub Action puisse assumer notre rôle. Toujours en version simplifiée, cela représente ça: GitHub Action assume web identity role

Nous allons compléter notre GitHub Action Workflow avec l’action configure-aws-credentials-for-github-actions. Pour ce faire, il faudra:

  1. Ajouter la permission à notre workflow d’utiliser un JSON Web Token GitHub.
  2. Ajouter la step avec notre GitHub Action configure-aws-credentials-for-github-actions tout en mettant notre aws_role_arn en paramètre de la step.

Ce qui nous donne le rendu final et fonctionnel suivant:

name: Hugo deploy website on S3

on:
  push:
    branches: [ main ]

permissions:
      id-token: write   # This is required for requesting the JWT
      contents: read    # This is required for actions/checkout

jobs:
  Build_and_Deploy:
    runs-on: ubuntu-latest
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - name: Git clone the repository
      uses: actions/checkout@v4
      with:
        submodules: 'true'
    - name: configure aws credentials
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::012345678912:role/GitHubOIDCRole # To replace with aws_role_arn
        role-session-name: githubActionHugoDeploy
        aws-region: eu-west-3
    # Sets up Hugo with latest version
    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
          hugo-version: 'latest'
          extended: true
    - name: Build
      run: hugo --minify
    - name: Deploy to S3
      run: hugo deploy --force

Avec le résultat suivant, à la suite d’un git push, via GitHub Action: GitHub action

Auto setup d’ACM (AWS Certificate Manager)

Dans la construction du site web, nous partons du principe dans l’article précédent que le nom de domaine (ou sous domaine) est hébergé sur Amazon Route 53 et que la Hosted Zone doit être créée manuellement.

Jusqu’à récemment, la création du certificat dans AWS Certificate Manger (ACM) devait aussi être manuelle. Chose révolue à la suite de ce commit qui peut se résumer au travers du snippet suivant:

resource "aws_acm_certificate" "hugo" {
  provider          = aws.aws_cloudfront # CloudFront uses certificates from US-EAST-1 region only
  domain_name       = local.dns_name
  validation_method = "DNS"
}

resource "aws_route53_record" "hugo" {
  for_each = {
    for dvo in aws_acm_certificate.hugo.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  allow_overwrite = true
  name            = each.value.name
  records         = [each.value.record]
  ttl             = 60
  type            = each.value.type
  zone_id         = data.aws_route53_zone.hugo.zone_id
}

resource "aws_acm_certificate_validation" "hugo" {
  provider                = aws.aws_cloudfront # CloudFront uses certificates from US-EAST-1 region only
  certificate_arn         = aws_acm_certificate.hugo.arn
  validation_record_fqdns = [for record in aws_route53_record.hugo : record.fqdn]
}

Information

Vous pouvez retrouver ce snippet directement dans la documentation officielle d’HashiCorp.

Nouveau domain name

Enfin, dernière nouveauté concernant le site: le changement de nom de domaine de blog.mehdilaruelle.ninja en mehdilaruelle.com lié notamment a l’augmentation du prix des noms de domaine global et surtout celui du .ninja.

Ce changement ma posé plusieurs défis, notamment:

  • Le changement de configuration de Hugo dans le config.toml (plutôt facile)
  • Le certificat (plutôt facile avec l’automatisation via Terraform)
  • La redirection de blog.mehdilaruelle.ninja vers mehdilaruelle.com sachant que l’hébergement du nom de domaine est situé côté OVH

Le dernier défi ma notamment poussé à mettre en place un mécanisme de redirection avec préservation du path (chose inexistante gratuitement côté OVH) en serverless via Amazon API Gateway mais cela fera l’objet d’un autre article.

Conclusion

Les différentes améliorations du site web m’ont apporté une expérience de release beaucoup plus fluide et transparente, notament via l’intégration de GitHub Action et des credentials dynamiques AWS. D’autre part, pour les mises à jour Terraform, vous pouvez passer par tfupdate au travers du pre-commit-terraform pour rester le plus à jour sur vos dépendances.

Information

Dans le repository Terraform pour déployer ce site, le pre-commit-terraform est utilisé.

Enfin, dans un prochain blog post, nous aurons l’occasion de parler plus en détail du mécanisme de redirection avec préservation du path en serverless via Amazon API Gateway. Si vous avez d’autres idées d’améliorations, n’hésitez pas à m’écrire.