Toets infrastruktuur as kode met Pulumi. Deel 1

Goeie middag vriende. In afwagting van die begin van 'n nuwe vloei teen die tempo "DevOps-praktyke en gereedskap" Ons deel 'n nuwe vertaling met jou. Gaan.

Toets infrastruktuur as kode met Pulumi. Deel 1

Die gebruik van Pulumi en algemene programmeertale vir infrastruktuurkode (Infrastruktuur as kode) bied baie voordele: die beskikbaarheid van vaardighede en kennis, uitskakeling van boilerplate in die kode deur abstraksie, gereedskap wat aan jou span bekend is, soos IDE's en linters. Al hierdie sagteware-ingenieursinstrumente maak ons ​​nie net meer produktief nie, maar verbeter ook die kwaliteit van ons kode. Daarom is dit net natuurlik dat die gebruik van algemene programmeertale ons in staat stel om nog 'n belangrike sagteware-ontwikkelingspraktyk bekend te stel - toetsing.

In hierdie artikel sal ons kyk hoe Pulumi ons help om ons infrastruktuur-as-kode te toets.

Toets infrastruktuur as kode met Pulumi. Deel 1

Hoekom toets infrastruktuur?

Voordat u in detail ingaan, is dit die moeite werd om die vraag te vra: "Waarom enigsins infrastruktuur toets?" Daar is baie redes hiervoor en hier is 'n paar van hulle:

  • Eenheidtoetsing van individuele funksies of fragmente van jou programlogika
  • Verifieer die verlangde toestand van die infrastruktuur teen sekere beperkings.
  • Opsporing van algemene foute, soos 'n gebrek aan enkripsie van 'n stoor emmer of onbeskermde, oop toegang vanaf die internet tot virtuele masjiene.
  • Kontroleer die implementering van infrastruktuurvoorsiening.
  • Voer looptydtoetse uit van toepassingslogika wat binne jou "geprogrammeerde" infrastruktuur loop om funksionaliteit na voorsiening na te gaan.
  • Soos ons kan sien, is daar 'n wye verskeidenheid opsies vir infrastruktuurtoetsing. Polumi het meganismes om op elke punt op hierdie spektrum te toets. Kom ons begin en kyk hoe dit werk.

Eenheid toetsing

Pulumi-programme word geskryf in algemene programmeertale soos JavaScript, Python, TypeScript of Go. Daarom is die volle krag van hierdie tale, insluitend hul gereedskap en biblioteke, insluitend toetsraamwerke, vir hulle beskikbaar. Pulumi is multi-wolk, wat beteken dat dit vir toetsing van enige wolkverskaffer gebruik kan word.

(In hierdie artikel, al is dit veeltalig en veelwolk, gebruik ons ​​JavaScript en Mocha en fokus ons op AWS. Jy kan Python gebruik unittest, Gaan toetsraamwerk, of enige ander toetsraamwerk waarvan jy hou. En natuurlik werk Pulumi uitstekend met Azure, Google Cloud, Kubernetes.)

Soos ons gesien het, is daar verskeie redes waarom jy dalk jou infrastruktuurkode wil toets. Een daarvan is konvensionele eenheidtoetsing. Omdat jou kode funksies kan hê - byvoorbeeld om CIDR te bereken, name, etikette, ens. - jy sal hulle waarskynlik wil toets. Dit is dieselfde as om gereelde eenheidstoetse vir toepassings in jou gunsteling programmeertaal te skryf.
Om 'n bietjie meer ingewikkeld te raak, kan jy kyk hoe jou program hulpbronne toewys. Om dit te illustreer, laat ons ons voorstel dat ons 'n eenvoudige EC2-bediener moet skep en ons wil seker wees van die volgende:

  • Gevalle het 'n merker Name.
  • Gevalle moet nie inlynskrif gebruik nie userData - ons moet 'n AMI (beeld) gebruik.
  • Daar behoort geen SSH aan die internet blootgestel te wees nie.

Hierdie voorbeeld is gebaseer op my voorbeeld aws-js-webbediener:

indeks.js:

"use strict";
 
let aws = require("@pulumi/aws");
 
let group = new aws.ec2.SecurityGroup("web-secgrp", {
    ingress: [
        { protocol: "tcp", fromPort: 22, toPort: 22, cidrBlocks: ["0.0.0.0/0"] },
        { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
    ],
});
 
let userData =
`#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &`;
 
let server = new aws.ec2.Instance("web-server-www", {
    instanceType: "t2.micro",
    securityGroups: [ group.name ], // reference the group object above
    ami: "ami-c55673a0"             // AMI for us-east-2 (Ohio),
    userData: userData              // start a simple web server
});
 
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;

Dit is die basiese Pulumi-program: dit ken eenvoudig 'n EC2-sekuriteitsgroep en 'n instansie toe. Daar moet egter op gelet word dat ons hier al drie reëls hierbo oortree. Kom ons skryf toetse!

Skryf van toetse

Die algemene struktuur van ons toetse sal soos gewone Mokka-toetse lyk:

ec2toetse.js

test.js:
let assert = require("assert");
let mocha = require("mocha");
let pulumi = require("@pulumi/pulumi");
let infra = require("./index");
 
describe("Infrastructure", function() {
    let server = infra.server;
    describe("#server", function() {
        // TODO(check 1): Должен быть тэг Name.
        // TODO(check 2): Не должно быть inline-скрипта userData.
    });
    let group = infra.group;
    describe("#group", function() {
        // TODO(check 3): Не должно быть SSH, открытого в Интернет.
    });
});

Kom ons skryf nou ons eerste toets: maak seker dat die gevalle die merker het Name. Om dit na te gaan, kry ons eenvoudig die EC2-instansievoorwerp en kontroleer die ooreenstemmende eienskap tags:

 // check 1: Должен быть тэг Name.
        it("must have a name tag", function(done) {
            pulumi.all([server.urn, server.tags]).apply(([urn, tags]) => {
                if (!tags || !tags["Name"]) {
                    done(new Error(`Missing a name tag on server ${urn}`));
                } else {
                    done();
                }
            });
        });

Dit lyk soos 'n gewone toets, maar met 'n paar kenmerke wat die moeite werd is om op te let:

  • Omdat ons navraag doen oor die toestand van 'n hulpbron voor ontplooiing, word ons toetse altyd in "plan" (of "voorskou") modus uitgevoer. Daar is dus baie eiendomme waarvan die waardes eenvoudig nie opgespoor sal word nie of nie gedefinieer sal word nie. Dit sluit alle uitseteienskappe in wat deur jou wolkverskaffer bereken is. Dit is normaal vir ons toetse - ons kontroleer slegs die invoerdata. Ons sal later na hierdie kwessie terugkeer wanneer dit by integrasietoetse kom.
  • Aangesien alle Pulumi-hulpbroneienskappe uitsette is, en baie van hulle asinchroon geëvalueer word, moet ons die toepassingsmetode gebruik om toegang tot die waardes te verkry. Dit is baie soortgelyk aan beloftes en 'n funksie then .
  • Aangesien ons verskeie eienskappe gebruik om die hulpbron-URN in die foutboodskap te wys, moet ons die funksie gebruik pulumi.allom hulle te kombineer.
  • Ten slotte, aangesien hierdie waardes asinchroon bereken word, moet ons Mocha se ingeboude asynchrone terugbelfunksie gebruik done of om 'n belofte terug te gee.

Sodra ons alles opgestel het, sal ons toegang hê tot die invoere as eenvoudige JavaScript-waardes. Eiendom tags is 'n kaart (assosiatiewe skikking), so ons sal net seker maak dit is (1) nie vals nie, en (2) daar is 'n sleutel vir Name. Dit is baie eenvoudig en nou kan ons enigiets toets!

Kom ons skryf nou ons tweede tjek. Dit is selfs eenvoudiger:

 // check 2: Не должно быть inline-скрипта userData.
        it("must not use userData (use an AMI instead)", function(done) {
            pulumi.all([server.urn, server.userData]).apply(([urn, userData]) => {
                if (userData) {
                    done(new Error(`Illegal use of userData on server ${urn}`));
                } else {
                    done();
                }
            });
        });

En laastens, kom ons skryf die derde toets. Dit sal 'n bietjie meer ingewikkeld wees, want ons soek die aanmeldreëls wat verband hou met die sekuriteitsgroep, waarvan daar baie kan wees, en die CIDR-reekse in daardie reëls, waarvan daar ook baie kan wees. Maar ons het dit reggekry:

    // check 3: Не должно быть SSH, открытого в Интернет.
        it("must not open port 22 (SSH) to the Internet", function(done) {
            pulumi.all([ group.urn, group.ingress ]).apply(([ urn, ingress ]) => {
                if (ingress.find(rule =>
                        rule.fromPort == 22 && rule.cidrBlocks.find(block =>
                            block === "0.0.0.0/0"))) {
                    done(new Error(`Illegal SSH port 22 open to the Internet (CIDR 0.0.0.0/0) on group ${urn}`));
                } else {
                    done();
                }
            });
        });

Dis al. Laat ons nou die toetse uitvoer!

Lopende toetse

In die meeste gevalle kan u toetse op die gewone manier uitvoer deur die toetsraamwerk van u keuse te gebruik. Maar daar is een kenmerk van Pulumi wat die moeite werd is om aandag aan te gee.
Tipies, om Pulumi-programme te laat loop, word die pulimi CLI (Command Line-koppelvlak) gebruik, wat die taallooptyd instel, die bekendstelling van die Pulumi-enjin beheer sodat bedrywighede met hulpbronne aangeteken en by die plan ingesluit kan word, ens. Daar is egter een probleem. Wanneer jy onder die beheer van jou toetsraamwerk hardloop, sal daar geen kommunikasie tussen die CLI en die Pulumi-enjin wees nie.

Om hierdie probleem te omseil, moet ons net die volgende spesifiseer:

  • Projeknaam, wat in die omgewingsveranderlike vervat is PULUMI_NODEJS_PROJECT (of, meer algemeen, PULUMI__PROJECT для других языков).
    Die naam van die stapel wat in die omgewingsveranderlike gespesifiseer word PULUMI_NODEJS_STACK (of, meer algemeen, PULUMI__ STACK).
    Jou stapel konfigurasie veranderlikes. Hulle kan verkry word deur gebruik te maak van 'n omgewingsveranderlike PULUMI_CONFIG en hul formaat is JSON-kaart met sleutel/waarde-pare.

    Die program sal waarskuwings uitreik wat aandui dat die verbinding met die CLI/enjin nie tydens uitvoering beskikbaar is nie. Dit is belangrik, want jou program sal eintlik niks ontplooi nie en dit kan as 'n verrassing kom as dit nie is wat jy bedoel het om te doen nie! Om vir Pulumi te vertel dat dit presies is wat jy nodig het, kan jy installeer PULUMI_TEST_MODE в true.

    Stel jou voor dat ons die projeknaam in moet spesifiseer my-ws, stapel naam dev, en AWS-streek us-west-2. Die opdragreël om Mokka-toetse uit te voer sal soos volg lyk:

    $ PULUMI_TEST_MODE=true 
        PULUMI_NODEJS_STACK="my-ws" 
        PULUMI_NODEJS_PROJECT="dev" 
        PULUMI_CONFIG='{ "aws:region": "us-west-2" }' 
        mocha tests.js

    Deur dit te doen, soos verwag, sal ons wys dat ons drie mislukte toetse het!

    Infrastructure
        #server
          1) must have a name tag
     	 2) must not use userData (use an AMI instead)
        #group
          3) must not open port 22 (SSH) to the Internet
    
      0 passing (17ms)
      3 failing
     
     1) Infrastructure
           #server
             must have a name tag:
         Error: Missing a name tag on server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     2) Infrastructure
           #server
             must not use userData (use an AMI instead):
         Error: Illegal use of userData on server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     3) Infrastructure
           #group
             must not open port 22 (SSH) to the Internet:
         Error: Illegal SSH port 22 open to the Internet (CIDR 0.0.0.0/0) on group

    Kom ons maak ons ​​program reg:

    "use strict";
     
    let aws = require("@pulumi/aws");
     
    let group = new aws.ec2.SecurityGroup("web-secgrp", {
        ingress: [
            { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
        ],
    });
     
    let server = new aws.ec2.Instance("web-server-www", {
        tags: { "Name": "web-server-www" },
        instanceType: "t2.micro",
        securityGroups: [ group.name ], // reference the group object above
        ami: "ami-c55673a0"             // AMI for us-east-2 (Ohio),
    });
     
    exports.group = group;
    exports.server = server;
    exports.publicIp = server.publicIp;
    exports.publicHostName = server.publicDns;
    

    En voer dan die toetse weer uit:

    Infrastructure
        #server
          ✓ must have a name tag
          ✓ must not use userData (use an AMI instead)
        #group
          ✓ must not open port 22 (SSH) to the Internet
     
     
     3 passing (16ms)

    Alles het goed afgeloop... Hoera! ✓✓✓

    Dit is al vir vandag, maar ons sal praat oor ontplooiingstoetsing in die tweede deel van die vertaling 😉

Bron: will.com

Voeg 'n opmerking