logo

 

Déployer un site statique S3 avec AWS CDK

Déployer un site statique S3 avec AWS CDK

Contenu

Deployer un site statique avec CDK

AWS propose de nombreux services, et plusieurs manières de déployer de manière automatisée son infrastructure. Dans cet article, nous découvrirons l’un de ces outils de déploiement automatique, AWS CDK, au travers de l’exemple d’un site statique déployé avec un bucket S3.

Pour aider au suivi, un repository github suivant les mêmes instructions est disponible, un lien pour l’état du projet à chaque étape sera en fin de chaque section.

Le site statique

Le site statique en tant que tel n’a pas d’importance, ainsi nous nous baserons sur le helloworld de react:

npx create-react-app cdk-example

Cette commande crée un nouveau dossier et initialise un projet react, qui sera compilé dans le dossier build. Si vous préférez utiliser un de vos propre projet, changez simplement les références au dossier build par son équivalent dans votre projet.

Pour référence, cet article a été écris avec create-react-app v5.0.1, le projet de référence à ce stade ressemble donc à:

.
├── node_modules
├── package.json
├── package-lock.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── README.md
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js

Projet à cette étape.

CDK

Le Cloud Development Kit de AWS est une librairie permettant de décrire son infrastructure AWS en JavaScript, et de déployer et synchroniser son infrastructure à partir ce cette description. Si vous connaissez Terraform, vous pouvez vous figurer une version de Terraform en syntaxe javascript, typescript, python, C#, java ou go et centrée autour de AWS. Pour cet article, nous utiliserons javascript.

L’avantage principal est qu’un développeur avec peu d’expérience devops peux comprendre et travailler avec le CDK dans une syntaxe connue, plutôt que d’apprendre un language nouveau dans son intégralité.

Configurer CDK

Avant de pouvoir utiliser le CDK, nous allons devoir le configurer et installer la CLI AWS v2, la CLI de CDK, et configurer l’accès au compte AWS sur lequel vous déploierez.

AWS propose un guide complet pour l’installation de la CLI que je vous laisse suivre.

Les sections suivantes sont une version résumée et traduite du guide AWS sur l’installation et configuration de AWS CDK, vous pouvez si vous le préférez consulter l’article original.

Installer l’AWS CDK CLI

La CLI est disponible simplement sur npm, il vous suffit donc de lancer la commande

npm i -g aws-cdk

Credentials

AWS recommande fortement l’utilisation de IAM Security Center pour la connexion à AWS via la CLI. La configuration de celui ci est cependant trop longue pour cet article. Si vous souhaitez vous simplifier la tache, vous pouvez utiliser les Access Tokens:

  • Connectez vous à la console AWS
  • Allez dans le service IAM
  • Dans la section Users, sélectionnez votre utilisateur (ou créez un nouvel utilisateur pour cet usage)
  • Dans l’onglet Security Credentials, cherchez la section Access Keys et cliquez sur Create access key
  • Sélectionnez Command Line Interface (CLI), cochez la case sur l’avertissement de sécurité, puis sur Next.
  • Ajoutez une description si vous le souhaitez, cliquez sur Next, et vous aurez votre access key.
  • Utilisez la commande aws configure pour configurer l’accès en ajoutant les clefs créées précédemment.

Bootstrap

Le CDK a besoin de certaines ressources créés en amont pour pouvoir faire son travail, fort heureusement, AWS permet de créer automatiquement ces données:

cdk bootstrap

Vous n’aurez besoin d’exécuter ceci qu’une seule fois pour tout le compte AWS, les autres utilisateurs du compte AWS n’auront pas besoin de configurer quoique ce soit de plus. Si vous voulez tout de même utiliser cette commande avec un compte aux droits restreints, les droits minimums que le compte doit avoir pour faire le bootstrap est:

Pour le compte 123456789012 dans la region eu-west-3.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "IAM",
            "Effect": "Allow",
            "Action": [
                "iam:GetRole",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:DeleteRolePolicy",
                "iam:DetachRolePolicy",
                "iam:AttachRolePolicy",
                "iam:PutRolePolicy"
            ],
            "Resource": [
                "arn:aws:iam::123456789012:role/cdk-*"
            ]
        },
        {
            "Sid": "CloudFormation",
            "Effect": "Allow",
            "Action": [
                "cloudformation:DescribeStackEvents",
                "cloudformation:CreateStack",
                "cloudformation:GetTemplate",
                "cloudformation:DeleteStack",
                "cloudformation:CreateChangeSet",
                "cloudformation:DescribeChangeSet",
                "cloudformation:ExecuteChangeSet",
                "cloudformation:DeleteChangeSet",
                "cloudformation:DescribeStacks"
            ],
            "Resource": "arn:aws:cloudformation:eu-west-3:123456789012:stack/CDKToolkit/*"
        },
        {
            "Sid": "S3",
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:SetBucketEncryption"
            ],
            "Resource": "*"
        },
        {
            "Sid": "SSM",
            "Effect": "Allow",
            "Action": [
                "ssm:PutParameter",
                "ssm:DeleteParameter"
            ],
            "Resource": "arn:aws:ssm:eu-west-3:123456789012:parameter/cdk-bootstrap/*/version"
        },
        {
            "Sid": "ECR",
            "Effect": "Allow",
            "Action": [
                "ecr:CreateRepository",
                "ecr:SetRepositoryPolicy",
                "ecr:DeleteRepository"
            ],
            "Resource": "arn:aws:ecr:eu-west-3:123456789012:repository/cdk-*"
        }
    ]
}

Il est cependant bien plus important de vérifier les permissions du role d’execution qui est créé lors de cette opération. Ce role sera utilisé pour tout les déploiement via le CDK, et est par défaut créé avec les droits administrateur, il convient donc de retourner dans IAM, rechercher le role cdk-abc123cde-cfn-exec-role-123456789012-eu-west-3 qui sera apparut, et le limiter aux actions qui doivent être autorisées pour le déploiement.

Pour référence, vous pouvez aussi consulter la documentation AWS officielle.

Ajouter CDK au projet

cdk init

AWS CDK propose une commande cdk init pour initialiser un nouveau projet utilisant CDK. Cependant, nous avons déjà notre projet existant.

Pour ajouter cdk au projet, nous allons créer un nouveau dossier, et initialiser un projet CDK dedans, et récupérer ce dont nous avons besoins:

mkdir cdk
cd cdk
cdk init --language=javascript

Note: Vous pouvez remplacer --language=javascript par --language=typescript pour avoir votre CDK en typescript et générer les fichiers avec.

L’initialisation de CDK nous donne un projet de cette forme:

.
├── bin
│   └── cdk.js
├── cdk.json
├── jest.config.js
├── lib
│   └── cdk-stack.js
├── package.json
├── package-lock.json
├── README.md
├── test
│   └── cdk.test.js

Nous pouvons récupérer presque tout les fichiers tel quel, il nous faudra seulement être plus prudent sur package.json, et ignorer le package-lock.json.

package.json

Nous devrons recopier les propriétés bin et scripts.cdk.

Nous devront aussi récupérer les dépendances:

npm i aws-cdk jest aws-cdk-lib constructs

Les fichiers de CDK

À ce stade, votre projet devrait ressembler à:

.
├── bin
│   └── cdk.js
├── cdk.json
├── jest.config.js
├── lib
│   └── cdk-stack.js
├── package.json
├── package-lock.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── README.md
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   ├── reportWebVitals.js
│   └── setupTests.js
└── test
    └── cdk.test.js

Les différentes choses que nous avons récupéré sont donc:

  • Un script cdk dans le package.json, pour faciliter l’utilisation de cdk.
  • Un lien vers le binaire bin/cdk.js dans le package.json, pour faciliter l’utilisation de cdk.
  • bin/cdk.js, qui est le point d’entrée de CDK, et sera utilisé pour configurer CDK (environment, compte AWS…).
  • lib/cdk-stack.js, qui est utilisé par bin/cdk.js et permet de configurer ce qui sera déployé.
  • cdk.json, qui similaire à eslintrc.json, permet de configurer CDK.

Projet à cette étape

CDK Stack

Nous avons maintenant tout ce qu’il nous faut pour commencer à déployer notre projet avec CDK.

Déployer un bucket S3

Dans lib/cdk-stack.js, nous pouvons ajouter:

const { Stack, RemovalPolicy, CfnOutput } = require('aws-cdk-lib')
const { Bucket } = require('aws-cdk-lib/aws-s3');

class CdkStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const websiteBucket = new Bucket(this, 'website', {
      versioned: false,
      removalPolicy: RemovalPolicy.DESTROY,
      autoDeleteObjects: true
    });

    new CfnOutput(this, 'bucketName', {
      value: websiteBucket.bucketName,
      description: 'The name of the s3 bucket',
      exportName: 'websiteBucketName',
    });
  }
}

module.exports = { CdkStack }

Nous déclarons donc un bucket S3 nommé website appartenant à une stack nommée CdkStack, qui ne versionne pas les fichiers, et qui détruira ses fichiers au moment d’être détruit.

Nous déclarons aussi une sortie bucketName qui nous affichera le nom du buscket S3 créé.

Note: Le nom fournit sera utilisé comme une partie du nom, mais son véritable nom sera de la forme cdkstack-website12345678-90abcdefghij, d’où l’importance de l’afficher. En cas de besoins, vous pouvez aussi retrouver la stack par son nom dans CloudFormation et regarder ses ressources.

Nous pouvons déployer:

cdk deploy

Si nous allons voir dans la console, nous trouverons bien notre bucket créé, mais il sera vide et non accessible.

Le projet à cette étape

Faire du bucket un site statique

Il ne nous reste maintenant qu’à envoyer nos fichiers, et rendre le bucket accessible:

const { BucketDeployment, Source } = require('aws-cdk-lib/aws-s3-deployment');

// ...

new BucketDeployment(this, 'deployment', {
  destinationBucket: websiteBucket,
  sources: [Source.asset('./build')],
  retainOnDelete: false
});

Nous créons ainsi un déploiement de fichiers nommé deployment, basé sur le contenu de build, qui cible websiteBucket (le bucket créé précédemment) et qui ne garde pas les fichiers lors de la suppression.

Note: Si ce n’est pas déjà fait, pensez à lancer npm run build pour générer le dossier build et le site web à partir de react.

Si nous déployons, nous verrons que notre bucket est redéployé, et contiens bien notre site, mais il n’est toujours pas accessible.

Le projet à cette étape.

Pour cela, dans la configuration de websiteBucket, nous devons ajouter:

    websiteIndexDocument: 'index.html',
    publicReadAccess: true,

Cela définira que notre page d’accueil est index.html, et ouvrira les droits de lecture publique sur le bucket, permettant d’accéder à la page.

Le projet à cette étape.

Et pour avoir l’URL, nous ajouterons une nouvelle sortie:

new CfnOutput(this, 'bucketWebsiteUrl', {
  value: websiteBucket.bucketWebsiteUrl,
  description: 'The website URL',
  exportName: 'websiteBucketWebsiteUrl',
});

Déployez, et vous verrez dans la sortie de CDK l’url de votre site, qui sera accessible.

Le projet à cette étape.

Conclusion

Nous avons vu comment initialiser, installer et configurer CDK pour le déploiement et comment déployer un site web statique. Il convient de remarquer que le site statique n’est accessible que en HTTP (pas de HTTPS) et indique dès le nom qu’il s’agit de quelque chose de déployé via S3.

Pour aller plus loin, nous pourrons ajouter CloudFront pour gérer le HTTPS et le DNS pour avoir un nom de domaine à nous.

Pour rechercher les modules accessibles par CDK et comment les configurer, consultez l’API de AWS CDK.