Categorie > Infrastructuur

Aan de slag met AWS Cloudformation

geschreven door Wilco van Dijk

Bron: Philipps Blog


AWS CloudFormation is een service die helpt bij het beheren van AWS resources door middel van sjablonen. Het stelt gebruikers in staat om infrastructuur als code te behandelen, waardoor het eenvoudiger wordt om consistente, reproduceerbare omgevingen te creëren. Het biedt voordelen zoals geautomatiseerde provisioning en configuratie, herhaalbaarheid van omgevingen (denk aan ontwikkel-, test- en productieomgeving) en versiebeheer van infrastructuur.

Vereisten

Voordat je aan de slag kunt gaan, zijn er enkele vereisten.

  • Je hebt een AWS account nodig. Als je nog geen account hebt kun je die hier aanmaken.

Basisconcepten

Sjablonen (templates) CloudFormation-sjablonen zijn JSON- of YAML-bestanden die de AWS-resources en hun configuraties beschrijven. Ik zal in mijn voorbeelden YAML gebruiken.

Stacks Een stack is een verzameling van AWS-resources die CloudFormation beheert als een enkele eenheid. Alle resources binnen een stack worden aangemaakt, bijgewerkt en verwijderd als een geheel.

Resources Dit zijn de componenten die in een sjabloon worden gedefinieerd, zoals Cognito, IAM rollen, S3-buckets, en RDS-databases etc..

Je eerste sjabloon maken

Een Cloudformation-sjabloon heeft een vaste structuur en bestaat uit een versiedatum en maximaal negen secties. Sommige zijn verplicht en de rest is optioneel.

AWSTemplateFormatVersion (verplicht) Bovenaan staat de versiedatum.

AWSTemplateFormatVersion: 2010-09-09

Dit bepaalt welke mogelijkheden de sjabloon zal hebben. De huidige versie die je op alle up-to-date sjablonen zult zien, is 2010-09-09.

MetaData (optioneel) Deze sectie kan worden gebruikt voor meer informatie over de sjabloon. Voorbeelden die ik heb gezien met deze sectie omvatten beschrijvingen van hoe resources zijn ingedeeld binnen de AWS CloudFormation Designer. Ik gebruik deze component niet.

Description (optioneel) Deze sectie kan worden gebruikt om jou als auteur of je teamgenoten te helpen begrijpen wat de sjabloon doet. Je zou een korte samenvatting van de sjabloon kunnen opnemen, wie het heeft geschreven, enz. Het is een optionele sectie van de sjabloon.

Description: Mijn eerste Cloudformation script waarin ik een S3 bucket aanmaak

Parameters (optioneel) Deze sectie kan worden gebruikt om variabelen in te stellen die je kunt aanpassen wanneer je de sjabloon implementeert. Vanuit een release pipeline zou je voor een ontwikkelomgeving andere waarden mee kunnen geven als voor een productieomgeving.

Environment: 
  Type: String
  Description: Identificatie van de omgeving. Toegestane waarden zijn d(evelopment), t(est), p(roduction)
  AllowedValues:
    - d
    - t
    - p
  Default: d
  ConstraintDescription: Gebruik geldige omgeving (d,t,p)

In het bovenstaande voorbeeld hebben we een parameter die een standaardwaarde heeft als er geen informatie wordt verstrekt. Zonder de standaardwaarde is invoer vereist wanneer de sjabloon wordt geïmplementeerd. Ook is de parameter ingesteld om slechts drie invoerwaarden als geldig te beschouwen. Dit is handig als je mensen die de sjabloon implementeren, wilt begeleiden naar bedrijfsstandaarden of de beschikbare opties voor die specifieke invoer. Meer informatie over de syntax kun je hier vinden.

Rules (optioneel) Deze sectie wordt gebruikt om complexe validaties uit te voeren op parameters en om waarden te berekenen op basis van deze parameters. Regels helpen om sjablonen flexibeler en robuuster te maken door ervoor te zorgen dat de ingevoerde waarden voldoen aan specifieke voorwaarden en dat ze correct worden gevalideerd voordat de sjabloon wordt geïmplementeerd.

Parameters:

  Environment: 
    Type: String
            ...

  NumberOfInstances:
    Description: Number of instances to launch
    Type: Number
    Default: 1
    MinValue: 1
    MaxValue: 5
    ConstraintDescription: Must be between 1 and 5

Rules:
  ProdEnvironmentRule:
    Assertions:
      - Assert: !Equals [ !Ref NumberOfInstances,  "5" ]
        AssertDescription: Prod environment must have 5 instances
    RuleCondition: !Equals [ !Ref Environment, p ]

In dit voorbeeld wordt gecontroleerd of er in de productieomgeving precies 5 instanties worden aangemaakt.

Mappings (optioneel) Voor een complexe implementatie kun je de mapping-sectie gebruiken om een sleutel aan een benoemde waarde te koppelen. Bijvoorbeeld als je op basis van de omgeving een bepaalde waarde wilt toekennen.

Mappings:
  QuantityOfInstances:
    d:
      qty: 1
    t:
      qty: 2
    p:
      qty: 5

Resources:
  DemoResource:
    Type: 'AWS::S3::Bucket'
    Properties:
      Tags:
        - Key: "InstanceQuantity"
          Value: !FindInMap [ QuantityOfInstances, !Ref Environment, qty ]

Je kunt die mappingtabel later in je sjabloon opvragen, zodat de juiste waarde wordt gekozen, afhankelijk van de omgeving waarin je implementeert.

Conditions (optioneel) Binnen deze sectie kun je helpen de sjabloon te beslissen of iets al dan niet moet worden gedaan op basis van de vraag of iets waar is of niet.

Conditions:
  isDevelopment: !Equals [!Ref Environment, d]
  isTest: !Equals [!Ref Environment, t]
  isProduction: !Equals [!Ref Environment, p]

Resources:
    instance0:
        Type: AWS::EC2::Instance
        Condition: isProduction
        Properties:
            ...
    ec20:
        Type: AWS::EC2::Instance
        Properties:
            ...
            InstanceType: !If [ isProduction, t3.large, t3.small ]
            ...

Condities kunnen worden gebruikt om te bepalen of een resource aangemaakt moet worden, maar ook om conditioneel waarden toe te kennen aan een eigenschap.

Transform (optioneel) Binnen deze sectie kun je een of meer macro's declareren en de sjabloon zal ze uitvoeren in de volgorde waarin ze zijn gespecificeerd. Ik ga hier ver niet op in, maar als je meer wilt weten is hier een duidelijk artikel waarin de mogelijkheden worden uitgelegd.

Resources (verplicht) Elke AWS CloudFormation-sjabloon zal een resource-sectie hebben en minstens één resource definiëren. Een overzicht van alle ondersteunde resources kun je hier terugvinden.

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  BucketName:
    Type: String
    Description: Name of bucket

Resources:
  MyS3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Ref BucketName

In dit eenvoudige voorbeeld wordt een S3 bucket aangemaakt. Ik zal dit voorbeeld verderop gebruiken om daadwerkelijk een bucket aan te maken.

Outputs (optioneel) Binnen deze sectie kun je informatie opvragen nadat de sjabloon en resources zijn aangemaakt. Je kunt bijvoorbeeld informatie vragen over een resource-naam, een IP-adres dat is aangemaakt, enz.

Outputs:
  S3Bucket:
    Description: Bucket created using this template.
    Value: !Ref S3Bucket

Je kunt deze informatie gebruiken als referentie of, bij complexere implementaties, de informatie verzamelen om door te geven aan andere automatiseringstaken.

Het sjabloon implementeren

Nu je weet hoe je een sjabloon moet opzetten, is het tijd om daadwerkelijk resources aan te maken. We pakken het voorbeeld van hierboven om een S3 bucket aan te maken en slaan deze op als S3.yaml.

Je kunt de sjabloon op verschillende manieren uitvoeren: via de AWS Management Console of, voor de gevorderde gebruiker, met de AWS Command Line Interface (CLI). In dit voorbeeld zullen we de sjabloon via de Management Console uitvoeren.

Ga naar de AWS Management Console. Ga vervolgens naar de CloudFormation service dashboard en kies voor "Create Stack".

Kies voor een bestaande template en selecteer het bestand s3.yaml. Klik vervolgens op 'Next'.

Vul hier de naam van de stack in en de waarden voor de verplichte input parameters van het sjabloon, in dit geval de naam van de aan te maken S3 bucket. Klik vervolgens twee keer op 'Next' en op 'Submit'. De resources worden nu aangemaakt. Tijdens het aanmaken van de stach wordt de tab 'Events' getoond. Hierin kun je zien hoe het aanmaakproces verloopt en ook foutmeldingen terugvinden, bijvoorbeeld als een bucket met een bepaalde naam al bestaat. Als alles goed verloopt dan is dit het resultaat.

Als je naar de tab 'Resources' wijzigt, dan krijg je een overzicht van alle aangemaakte resources.

Beheer en updates

Gebruik de AWS Management Console of de CLI om bestaande stacks te beheren en bij te werken. Het beheren van stacksvereist aandacht voor verschillende aspecten om effectief en veilig te werken.

Updaten

Je kunt een Cloudformation-sjabloon uitbreiden met aanvullende specificaties en opnieuw uitvoeren. De stack zal dan worden bijgewerkt. Het is van essentieel belang om veranderingen zorgvuldig te controleren en te testen, aangezien onvoorziene wijzigingen in de resourceconfiguratie problemen kunnen veroorzaken.

Tijdens het deployen en bijwerken van stacks kunnen verschillende foutstatussen optreden, zoals 'ROLLBACK_IN_PROGRESS' wanneer een update mislukt en AWS probeert de vorige werkende staat te herstellen. Dit zorgt ervoor dat de infrastructuur in een consistente staat blijft

Deletion Policy

Er zijn resources waarvan je wilt dat ze niet per ongeluk worden verwijderd als er een stack wordt bijgewerkt, bijvoorbeeld een database waarin bedrijfskritische gegevens zijn opgeslagen. Cloudformation biedt diverse beleidsopties voor het verwijderen van resources. Met de 'Deletion Policy'-optie kun je bepalen of een resource moet worden bewaard (Retain), verwijderd (Delete), of een snapshot moet maken (Snapshot) wanneer een stack wordt verwijderd, waardoor je meer controle hebt over het beheer van je infrastructuur en het behoud van cruciale gegevens.

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyS3Bucket:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain

Statussen

Een stack in AWS CloudFormation kan verschillende statussen hebben, afhankelijk van de fase waarin het zich bevindt en eventuele fouten die optreden. Hier zijn enkele van de belangrijkste statussen:

  1. CREATE_IN_PROGRESS: De stack wordt momenteel aangemaakt.

  2. CREATE_COMPLETE: De stack is succesvol aangemaakt.

  3. CREATE_FAILED: De aanmaak van de stack is mislukt.

  4. ROLLBACK_IN_PROGRESS: Een fout heeft plaatsgevonden tijdens het maken of bijwerken van de stack, en AWS probeert de vorige werkende staat te herstellen.

  5. ROLLBACK_COMPLETE: De rollback is voltooid en de stack is teruggezet naar de vorige werkende staat.

  6. ROLLBACK_FAILED: De rollback is mislukt.

  7. DELETE_IN_PROGRESS: De stack wordt momenteel verwijderd.

  8. DELETE_COMPLETE: De stack is succesvol verwijderd.

  9. DELETE_FAILED: Het verwijderen van de stack is mislukt.

  10. UPDATE_IN_PROGRESS: De stack wordt momenteel bijgewerkt.

  11. UPDATE_COMPLETE: De stack is succesvol bijgewerkt.

  12. UPDATE_COMPLETE_CLEANUP_IN_PROGRESS: De update is voltooid en CloudFormation is bezig met het opruimen van de tijdelijke resources.

  13. UPDATE_ROLLBACK_IN_PROGRESS: Een fout is opgetreden tijdens de update en AWS probeert de vorige werkende staat te herstellen.

  14. UPDATE_ROLLBACK_COMPLETE: De rollback van de update is voltooid.

  15. UPDATE_ROLLBACK_FAILED: De rollback van de update is mislukt.

Deze statussen helpen je om te begrijpen in welke fase de stack zich bevindt en of er fouten zijn opgetreden tijdens de creatie, update of verwijdering van de stack.

Geavanceerde functies

AWS CloudFormation ondersteunt ingebouwde functies in je sjablonen. Deze functies variëren van het verwijzen naar andere resources tot het bouwen van aangepaste tekenreeksen of het importeren van waarden uit andere stacks.

Ik behandel de functies die je het vaakst zult gebruiken, met enkele praktische voorbeelden. Raadpleeg de volledige documentatie over sjabloonfuncties voor een overzicht van alle ondersteunde functies.

Ref

!Ref wordt gebruikt om naar andere resources of parameters in je sjabloon te verwijzen. Afhankelijk van de resource geeft het de gegevens terug die doorgaans het meest nodig zijn van die resource. Bijvoorbeeld, voor een S3-bucket geeft het de naam van de bucket terug en voor een ACM-certificaat zal het de ARN (Amazon Resource Name) retourneren.

!Ref S3Bucket

GetAtt

De meeste resources stellen je in staat om extra informatie op te vragen naast wat beschikbaar is via !Ref. Je zult deze vaak gebruiken om resources samen te laten werken. In het documentatievoorbeeld van de sjabloon gebruikten we het om toegang te krijgen tot de WebsiteUrl van de S3-bucket.

De verkorte syntaxis van YAML stelt je in staat om de resource en het attribuut te specificeren via !GetAtt RESOURCE.ATTRIBUTE.

!GetAtt WebBucket.WebsiteURL

Sub

Met de functie !Sub kun je een tekenreeks bouwen en delen daarvan vervangen door waarden uit variabelen. Deze variabelen kunnen van alles zijn, variërend van de resultaten van !Ref of !GetAtt-oproepen tot het gebruik van !If om variabelen in te stellen op basis van sjabloonparameters.

De meest voorkomende gebruiksscenario's voor !Sub zijn:

  • Het maken van een tekenreeks waarin je de resultaten van !Ref of !GetAtt wilt invoegen.

  • Het creëren van grote tekstblokken die je wilt parametriseren, zoals een configuratiebestand voor een EC2-instance.

Ref of GetAtt insluiten

De verkorte syntaxis van !Sub heeft nog een handige truc wanneer je alleen waarden wilt gebruiken die toegankelijk zijn via !Ref of !GetAtt. Door de resourcenaam te plaatsen in ${RESOURCE} kun je hetzelfde resultaat krijgen als met !Ref en via ${RESOURCE.ATTRIBUTE} kun je de waarden ophalen die je normaal gesproken met !GetAtt zou krijgen.

Stel dat we een IAM-beleid willen schrijven dat toegang verleent tot alle bestanden in een bucket. Hiervoor hebben we de ARN van de bucket nodig en moeten we een wildcard aan het einde van die ARN toevoegen. Door de !Ref-waarde van de bucket te gebruiken, kunnen we de bucketnaam verkrijgen en de ARN opbouwen.

Action:
  - "s3:GetObject"
Effect: "Allow"
Resource:
  - !Sub arn:aws:s3:::${WebBucket}/*

Tijdens de deployment wordt ${WebBucket} vervangen door de naam van de bucket.

Aangezien de S3-bucketresource nu ondersteunt dat de ARN (Amazon Resource Name) via !GetAtt wordt opgehaald, kunnen we dit ook korter schrijven. Om toegang te krijgen tot elk bestand in de bucket, moeten we een wildcard toevoegen.

Action:
  - "s3:GetObject"
Effect: "Allow"
Resource:
  - !Sub ${WebBucket.Arn}/*

Select

Met de functie !Select kun je één item uit een lijst kiezen. Dit is vooral handig in combinatie met de functie !Split, die parameters of attributen van resources opdeelt, zodat je specifieke delen kunt selecteren.

!Select [2, !Split ['/', !GetAtt 'WebBucket.WebsiteURL']]

Join

Met de functie !Join kun je een lijst met elementen omzetten in een tekenreeks. Bijvoorbeeld, je kunt een lijst met Security Groups omzetten in een tekenreeks waarin de groepen door komma's worden gescheiden.

Outputs:
  LoadBalancerSecurityGroups:
    Description: Security Groups associated with our Main Loadbalancer
    Value: !Join [',', !GetAtt LoadBalancer.SecurityGroups]

Split

De meest voorkomende toepassing van de functie !Split is het opsplitsen van een waarde die is opgevraagd van een resource in hetzelfde sjabloon of na het importeren ervan uit een andere stack.

Bijvoorbeeld, wanneer we een S3-bucket maken die een statische website host en we willen deze bucket achter een CloudFront-distributie plaatsen. Om CloudFront te configureren, moeten we de domeinnaam van de S3 Web Bucket krijgen. De returnwaarde van de !GetAtt-oproep naar de S3-bucket retourneert echter de volledige URL, wat betekent dat we de https://-prefix moeten verwijderen. Dit kan worden bereikt met de functies !Split en !Select.

Origins:
  - DomainName: !Select [2, !Split ['/', !GetAtt 'WebBucket.WebsiteURL']]

Natuurlijk zouden we ook !Sub kunnen gebruiken om de URL zelf te bouwen, aangezien deze een bekend formaat heeft, maar dit is gewoon een nettere oplossing. En ditzelfde patroon kan worden gebruikt voor elke returnwaarde van elke resource. In combinatie met !Sub kun je zelfs een complexere tekenreeks bouwen die een returnwaarde splitst, verschillende delen selecteert en ze samenstelt met variabelen in een !Sub-tekenreeks.

If

Definieert voorwaardelijke expressies. Het voert verschillende acties uit afhankelijk van of de opgegeven voorwaarde waar of onwaar is. Bijvoorbeeld, je kunt verschillende waarden toewijzen op basis van een parameter die door de gebruiker is opgegeven.

!If [ isProduction, t3.large, t3.small ]

Equals

De functie !Equals in een CloudFormation-script wordt gebruikt om te controleren of twee waarden gelijk zijn aan elkaar. Dit is handig voor het uitvoeren van voorwaardelijke logica binnen je sjabloon.

!Equals [ !Ref Environment, p ]

Pseudo parameters

Pseudo-parameters in AWS CloudFormation zijn ingebouwde parameters die je kunt gebruiken in je sjablonen zonder dat je ze expliciet hoeft te definiëren. Ze bieden handige informatie over je stack en de omgeving waarin de stack wordt gedeployed.

Hier zijn enkele van de meest voorkomende pseudo-parameters:

AWS::AccountId Het AWS-account-ID waarin de stack wordt gedeployed.

AWS::Region De regio waarin de stack wordt gedeployed, bijvoorbeeld "eu-west-1".

AWS::StackName De naam van de stack.

AWS::StackId Het unieke ID van de stack.

AWS::NoValue Gebruik deze parameter om een eigenschap of parameter te verwijderen indien een voorwaarde onwaar is.

AWS::Partition De naam van de AWS-partitie waar de resource zich bevindt (bijvoorbeeld "aws" voor commerciële regio's, "aws-cn" voor China-regio's).

In het script kun je de parameters als volgt opnemen:

!Ref 'AWS::Region'

of

!Sub 'my-bucket-${AWS::AccountId}'

Deze pseudo-parameters maken het gemakkelijker om dynamische en herbruikbare sjablonen te maken, omdat ze je toegang geven tot essentiële informatie zonder dat je extra parameters hoeft toe te voegen.

Best practices

Het opzetten van CloudFormation-scripts kan je helpen om je infrastructuur efficiënter en consistenter te beheren. Hier zijn enkele best practices die je kunt volgen:

Sjabloonontwerp Schrijf efficiënte en herbruikbare sjablonen door modulaire en geneste sjablonen te gebruiken.

Beveiligingsoverwegingen Gebruik IAM-rollen en policies om de beveiliging van je CloudFormation-stacks te waarborgen.

Versiebeheer Houd je CloudFormation-sjablonen bij in een versiebeheersysteem zoals Git. Dit maakt het makkelijker om wijzigingen bij te houden en terug te rollen indien nodig.

Deze best practices helpen je om robuuste, efficiënte en veilige CloudFormation-sjablonen te maken die je infrastructuurbeheer vereenvoudigen en verbeteren.

Voordelen

De voordelen van het gebruik van Cloudformation zijn:

Consistentie Met CloudFormation kun je je infrastructuur op een consistente manier definiëren en implementeren, waardoor je voorkomt dat je handmatig instellingen moet aanpassen en mogelijke fouten introduceert.

Automatisering Door het gebruik van sjablonen kun je je infrastructuur volledig automatiseren, wat tijd en moeite bespaart en de kans op menselijke fouten vermindert.

Versiebeheer Je kunt wijzigingen aan je infrastructuur bijhouden en eenvoudig terugdraaien indien nodig, wat helpt om de stabiliteit en betrouwbaarheid te waarborgen.

Herbruikbaarheid Je kunt sjablonen hergebruiken voor verschillende projecten en omgevingen, wat je veel werk bespaart en zorgt voor consistentie tussen verschillende omgevingen.

Conclusie

AWS CloudFormation is een krachtige tool voor het beheren van infrastructuur als code. Door de hierboven besproken basisprincipes en best practices te volgen, kun je snel en efficiënt aan de slag met CloudFormation.

Heeft dit artikel jou op weg geholpen?  Buy Me A Coffee

Infrastructure as Code - AWS Cognito User Pool

Wilco van Dijk
Lees meer

Visual Studio inrichten voor AWS ontwikkeling

Wilco van Dijk
Lees meer

.Net configuratie opslaan in AWS Secrets Manager

Wilco van Dijk
Lees meer