En af de mest frustrerende udfordringer i applikationsudvikling i dag er miljøparitet. Mens de seneste år har vist, at virtualiserings- og containeriseringsværktøjer som Vagrant og Docker (og ActiveStates eget State Tool) kan sikre, at de operativsystemer og afhængigheder, der driver en applikations infrastruktur, er konsistente mellem miljøer, er eksterne afhængigheder næsten umulige at replikere i et ikke-produktionsmiljø.
I en verden, hvor afhængigheder fra tredjeparter er blevet uigenkaldeligt sammenflettet med kerneforretningslogikken i næsten alle softwareprojekter, bliver det stadig vanskeligere at holde udviklings-, staging- og produktionsmiljøer konsistente med hinanden. Mens nogle produkter med selvhostede lookalikes – såsom Minio til Amazon S3 – letter smerten ved at administrere flere implementeringer af en enkelt tjeneste, gør det ikke meget for at lette udfordringen med konfigurationsstyring på tværs af miljøer.
Når produktion, staging, udvikling, Bobs lokale maskine og QE-miljøet alle kræver en anden implementering af en given tjeneste, bliver det mere og mere upraktisk at sende konfigurationsfiler frem og tilbage eller at stole på komplekse betingelser for at bestemme, hvilken implementering et givet miljø skal tale til. Behovet for fleksibilitet understreger også vanskeligheden ved disse løsninger i et storskala-miljø. Hvad nu, hvis Bobs lokale maskine f.eks. midlertidigt skal tale med en tjeneste, der er reserveret til Staging-miljøet?
Miljøvariabler i Python
Konfiguration på tværs af miljøer er en plage, men heldigvis er de ovenfor skitserede problemer blevet så almindelige i de seneste år, at de næsten er løst. Takket være støtten fra open source-fællesskabet og evangeliseringen af best-practices som 12 Factor Application er der i de seneste år sket et skift fra filbaseret programkonfigurationshåndtering til miljøvariabelbaseret konfigurationshåndtering.
Miljøvariabler, der findes i alle større operativsystemer, er – ligesom navnet antyder – variabler, der implementeres på miljøniveau for at definere den måde, som programmer, der kører under det, skal opføre sig på. I enklere vendinger er de program-agnostiske variabler, der forvaltes uden for en given proces. Den primære fordel ved at bruge miljøvariabler er, at det giver udviklere mulighed for at definere, hvordan et program skal køre uden at ændre en linje kode.
Hvis Bobs lokale maskine f.eks. skal tale med den CDN-tjeneste, der er reserveret til Staging-miljøet, kan han ændre miljøvariablen CDN_URL
, så den afspejler, hvad der er defineret i Staging, uden at skulle røre ved nogen administreret kode. Endnu vigtigere er det, at Bob på denne måde kan definere mock- eller interne tjenester til brug for enheds- og integrationstests, alt sammen uden at skulle skrive en eneste linje ekstra kode.
Definering af miljøvariabler
Mens det at definere miljøvariabler generelt er OS-afhængigt, har langt de fleste programmeringssprog abstraheret disse forskelle gennem brug af udviklingspakker som Pythons dotenv-projekt. I stedet for at skulle definere en API_USER
miljøvariabel på OS-niveau kan en lokalt gitignored .env
fil f.eks. vedligeholde miljøvariabler på tværs af udviklingsmiljøer. Dette giver udviklere mulighed for at bruge en lokalt administreret konfigurationsfil til at indstille miljøvariabler, samtidig med at det muliggør konfiguration via “ægte” miljøvariabler i miljøer, der ikke er udviklingsmiljøer.
Som eksempel er her en simpel .env
-fil, som en udvikler kan bruge i sit lokale miljø:
APP_ENVIRONMENT=localAPP_NAME=localhostQUEUE_DRIVER=syncAPI_USER=bob
På den anden side kan produktionsmiljøet definere sine miljøvariabler i en Dockerfil, hvilket begge er gyldige metoder til at vedligeholde miljøvariabler.
Hentning af miljøvariabler
Uanset hvordan miljøvariabler er defineret, kan de altid hentes i Python ved hjælp af os.getenv()
-metoden:
import os# Get environment variablesUSER = os.getenv('API_USER')
Opmærksomheden henledes på, at i tilfælde af at miljøvariablen er udefineret, vil værdien som standard være None
.
Gå i gang med hemmeligheder
Nu er miljøvariabler, selv om de er en glimrende løsning til håndtering af forskellige konfigurationer på tværs af miljøer, ikke en mirakelkur. I dagens udviklingsklima skal sikkerhed være en topprioritet, og følsomme data skal opbevares på en sikker måde.
Uheldigvis er miljøvariabler i sig selv ikke sikre. Selv om de gør et godt stykke arbejde med at lagre konfigurationsdata, bør den måde, hvorpå vi definerer mere følsomme data som adgangskoder, API-nøgler og krypteringsnøgler, kræve større omhu. Det er her, at hemmeligheder kommer ind i billedet. Secrets er krypteret i hvile og bør kun hentes i en enkelt runtime efter behov for at reducere chancerne for et databrud. På denne måde kan du, selv hvis din hostingudbyder bliver kompromitteret, være sikker på, at dine følsomme hemmeligheder er låst godt inde.
Skabelse af &Håndtering af hemmeligheder med state-værktøjet
Så, hvordan opretter og håndterer vi hemmeligheder? Der findes en række forskellige måder at løse dette problem på, men ActiveState’s State Tool er en fremragende løsning til Python-sproget. I lighed med virtualenv
eller pipenv
er State Tool en grænseflade til forvaltning af virtuelle miljøer, der forhindrer krydskontaminering af Python-installationer og -konfigurationer mellem projekter. Det, der adskiller det fra andre værktøjer til administration af virtuelle miljøer, er dets integration med ActiveState-platformen, hvilket giver mulighed for en central grænseflade til administration af miljøkonfigurationer og, ja, hemmeligheder.
Hvor vi kan drage fordel af State Tool’s muligheder for administration af hemmeligheder, skal vi først bruge State Tool til at opsætte et virtuelt miljø i vores projektmappe. For at gøre dette skal du først identificere det ActiveState-projekt, du skal arbejde med (i denne vejledning kan du bruge mit projekt zachflower/envs-vs-secrets-demo
, så længe du har en gratis ActiveState Platform-konto, eller du kan oprette dit eget). Derefter skal du udføre kommandoen state activate
for dit givne projekt:
$ state activate zachflower/envs-vs-secrets-demo Where would you like to checkout zachflower/envs-vs-secrets-demo? /home/zach/Projects/miscellaneous/activestate-variables/zachflower/envs-vs-secrets-demoActivating state: zachflower/envs-vs-secrets-demoThe State Tool is currently in beta, we are actively changing and adding features based on developer feedback.Downloading required artifactsDownloading 1 / 1 Installing 0 / 1 0 %You are now in an 'activated state', this will give you a virtual environment to work in that doesn't affect the rest of your system.Your 'activated state' allows you to define scripts, events and constants via the activestate.yaml file at the root of your project directory.To expand your language and/or package selection, or to define client-side encrypted secrets, please visit https://platform.activestate.com/zachflower/envs-vs-secrets-demo.To try out scripts with client-side encrypted secrets we've created a simple script for you in your activestate.yaml, try it out by running 'helloWorld'
Som du kan se, opretter kommandoen activate det virtuelle miljø som defineret i dit ActiveState-projekt. I tilfælde af at projektet endnu ikke er blevet konfigureret, vil et simpelt projekt blive sat i gang med standardparametre for at give dig et eksempel på, hvordan alting skal gå sammen. Denne konfiguration gemmes i en fil i roden af din projektmappe ved navn activestate.yaml
.
Konfigurationsfil til hemmeligheder & Mere
Den activestate.yaml
fil definerer en udviklingskørselstid, som dit program skal køre under. For eksempel definerer standardfilen et simpelt script, der bruger en hemmelighed, samt et par hændelseslyttere, der udfører handlinger, når en defineret hændelse indtræffer:
project: https://platform.activestate.com/zachflower/envs-vs-secrets-demoscripts:# This script uses a secret. Note that you can define your own secrets at# https://platform.activestate.com/zachflower/envs-vs-secrets-demo/scripts - name: helloWorld value: echo ${secrets.user.world}events: # This is the ACTIVATE event, it will run whenever a new virtual environment is created (eg. by running `state activate`) # On Linux and macOS this will be ran as part of your shell's rc file, so you can use it to set up aliases, functions, environment variables, etc. - name: ACTIVATE constraints: os: macos,linux value: | echo "You are now in an 'activated state', this will give you a virtual environment to work in that doesn't affect the rest of your system." echo "" echo "Your 'activated state' allows you to define scripts, events and constants via the activestate.yaml file at the root of your project directory." echo "" echo "To expand your language and/or package selection, or to define client-side encrypted secrets, please visit https://platform.activestate.com/zachflower/envs-vs-secrets-demo." echo "" echo "To try out scripts with client-side encrypted secrets we've created a simple script for you in your activestate.yaml, try it out by running 'helloWorld'"
Selv om der ikke er noget særligt banebrydende her, burde den potentielle styrke af denne fil være umiddelbart indlysende. For eksempel giver følgende script et grundlæggende eksempel på, hvordan man kan bruge hemmeligheder i konfigurationsfilen:
scripts:# This script uses a secret. Note that you can define your own secrets at# https://platform.activestate.com/zachflower/envs-vs-secrets-demo/scripts - name: helloWorld value: echo ${secrets.user.world}
Når kommandoen helloWorld
udføres (fra en aktiveret tilstand), vil den gengive værdien af hemmeligheden user.world
, og i tilfælde af, at hemmeligheden endnu ikke er defineret, vil den bede om en værdi:
$ helloWorldThe action you are taking uses a secret that has not been given a value yet.Name: worldDescription: - (This secret has no description, you can set one via the web dashboard)Scope: user (Only you can access the value) Please enter a value for secret "world": ******
Anvendelse af hemmeligheder
Selv om eksemplet er relativt forenklet, så kommer den sande værdi af hemmeligheder fra aktiveringsbegivenhederne. I stedet for at hente en hemmelig værdi inden for rammerne af et script kan miljøvariabler defineres ved hjælp af hentede hemmeligheder uden nogensinde at eksponere disse hemmeligheder uden for dette sikre miljø:
project: https://platform.activestate.com/zachflower/envs-vs-secrets-demo?commitID=5fd1c161-c5a4-480c-8aba-29d8ab361b42events: - name: ACTIVATE constraints: os: macos,linux value: | export WORLD=${secrets.user.world}
Nu, hvis user.world
hemmeligheden er defineret, vil WORLD
miljøvariablen blive defineret og kan hentes som enhver anden miljøvariabel:
$ echo $WORLDworld!
Hvis den imidlertid ikke er defineret, vil brugeren blive bedt om at definere den ved aktivering af det virtuelle ActiveState-miljø:
The action you are taking uses a secret that has not been given a value yet.Name: helloDescription: - (This secret has no description, you can set one via the web dashboard)Scope: user (Only you can access the value) Please enter a value for secret "world": ******
Påfaldende, ikke?
Det går videre
Konfigurationsstyring i applikationsudvikling er for det meste et løst problem, men det er styring af hemmeligheder bare ikke endnu. Antallet af projekter, der har tjekket følsomme data ind i et versionsstyringsrepositorium, er svimlende, og det er noget selv højt respekterede virksomheder har gjort, men ved hjælp af korrekt sikkerhedshygiejne og produkter som ActiveState’s State Tool bliver det nemmere for hver dag, der går, at holde følsomme konfigurationsdata sikre og sikre.
- Prøv det selv ved at oprette en gratis ActiveState Platform-konto og downloade State Tool for at forenkle administration af hemmeligheder.
- Du kan også se vores webinar om, hvordan du administrerer delte hemmeligheder ved hjælp af State Tool
Relaterede blogs:
Gehemmeligheden bag administration af delte hemmeligheder
Udviklere kan dele hemmeligheder hurtigt og nemt uden at ofre sikkerheden