En av de mest frustrerande utmaningarna inom programutveckling idag är miljöparitet. Medan de senaste åren har visat att virtualiserings- och containeriseringsverktyg som Vagrant och Docker (och ActiveStates eget State Tool) kan se till att de operativsystem och beroenden som driver en applikations infrastruktur är konsekventa mellan olika miljöer, är det nästan omöjligt att replikera externa beroenden i en icke-produktionsmiljö.

I en värld där beroenden från tredje part har blivit oåterkalleligen sammanflätade med kärnverksamhetslogiken i nästan alla mjukvaruprojekt blir det allt svårare att hålla utvecklings-, staging- och produktionsmiljöer konsekventa med varandra. Även om vissa produkter med självhyst lookalikes – som Minio till Amazon S3 – underlättar hanteringen av flera distributioner av en enda tjänst, underlättar det inte särskilt mycket för konfigurationshanteringen mellan olika miljöer.

När produktion, staging, utveckling, Bobs lokala maskin och QE-miljön alla kräver olika distributioner av en viss tjänst, blir det alltmer opraktiskt att skicka konfigurationsfiler fram och tillbaka eller att förlita sig på komplexa villkor för att avgöra vilken distribution som en viss miljö ska prata med. Behovet av flexibilitet visar också på svårigheten med dessa lösningar i en storskalig miljö. Vad händer till exempel om Bobs Local Machine tillfälligt behöver tala med en tjänst som är reserverad för Staging-miljön?

Miljövariabler i Python

Konfigurering mellan olika miljöer är en plåga, men tack och lov har de problem som beskrivs ovan blivit så pass vanliga under de senaste åren att de är så gott som lösta. Tack vare stödet från öppen källkodssamhället och evangelisationen av bästa praxis som 12 Factor Application har det under de senaste åren skett ett skifte från filbaserad programkonfigurationshantering till miljövariabelbaserad konfigurationshantering.

Miljövariabler, som finns i alla större operativsystem, är – precis som namnet antyder – variabler som implementeras på miljönivå för att definiera hur program som körs under den ska bete sig. Förenklat kan man säga att de är applikationsoberoende variabler som hanteras utanför ramen för en viss process. Den främsta fördelen med att använda miljövariabler är att detta gör det möjligt för utvecklare att definiera hur ett program ska köras utan att ändra en rad kod.

Om Bobs lokala maskin till exempel behöver prata med CDN-tjänsten som är reserverad för Staging-miljön, kan han ändra miljövariabeln CDN_URL så att den återspeglar vad som är definierat i Staging utan att behöva röra vid någon hanterad kod. Ännu viktigare är att detta gör det möjligt för Bob att definiera mock- eller interna tjänster för användning med enhets- och integrationstester, allt utan att behöva skriva en enda rad extra kod.

Definiering av miljövariabler

Och även om det generellt sett är OS-beroende att definiera miljövariabler, så har den stora majoriteten av programmeringsspråken abstraherat dessa skillnader genom användning av utvecklingspaket som Pythons dotenv-projekt. I stället för att behöva definiera en API_USER miljövariabel på OS-nivå kan till exempel en lokalt gitignorerad .env-fil upprätthålla miljövariabler i olika utvecklingsmiljöer. Detta gör det möjligt för utvecklare att använda en lokalt hanterad konfigurationsfil för att ställa in miljövariabler, samtidigt som det möjliggör konfiguration via ”äkta” miljövariabler i miljöer som inte är utvecklingsmiljöer.

Som exempel finns här en enkel .env-fil som en utvecklare kan använda i sin lokala miljö:

APP_ENVIRONMENT=localAPP_NAME=localhostQUEUE_DRIVER=syncAPI_USER=bob

På andra sidan kan produktionsmiljön definiera sina miljövariabler i en Docker-fil, vilka båda är giltiga metoder för att upprätthålla miljövariabler.

Hämtning av miljövariabler

Oavsett hur miljövariabler definieras kan de alltid hämtas i Python med hjälp av os.getenv()-metoden:

import os# Get environment variablesUSER = os.getenv('API_USER')

Observera att om miljövariabeln är odefinierad kommer värdet att vara None som standard.

Genom att komma igång med Secrets

Men även om miljövariabler är en utmärkt lösning för att hantera olika konfigurationer i olika miljöer, är de inte en patentlösning. I dagens utvecklingsklimat måste säkerheten ha högsta prioritet och känsliga data måste förvaras på ett säkert sätt.

Tyvärr är miljövariabler i sig själva inte säkra. Även om de gör ett bra jobb när det gäller att lagra konfigurationsdata bör det sätt på vilket vi definierar mer känsliga data som lösenord, API-nycklar och krypteringsnycklar kräva större försiktighet. Det är här hemligheter kommer in i bilden. Secrets är krypterade i vila och bör endast hämtas i en enda körning vid behov för att minska oddsen för ett dataintrång. På detta sätt kan du vara säker på att dina känsliga hemligheter är ordentligt inlåsta även om din webbhotellleverantör blir utsatt.

Skapa &Hantera hemligheter med State Tool

Hur skapar och hanterar vi alltså hemligheter? Det finns ett antal olika sätt att ta itu med det här problemet, men ActiveState’s State Tool är en utmärkt lösning för språket Python. I likhet med virtualenv eller pipenv är State Tool ett gränssnitt för hantering av virtuella miljöer som förhindrar korskontaminering av Pythoninstallationer och konfigurationer mellan projekt. Det som skiljer det från andra verktyg för hantering av virtuella miljöer är integrationen med ActiveState-plattformen, vilket möjliggör ett centralt gränssnitt för hantering av miljökonfigurationer och, ja, hemligheter.

För att vi ska kunna dra nytta av State Tools funktioner för hantering av hemligheter måste vi först använda State Tool för att skapa en virtuell miljö i vår projektkatalog. För att göra detta identifierar du först det ActiveState-projekt som du ska arbeta med (för den här handledningen kan du använda mitt projekt zachflower/envs-vs-secrets-demo så länge du har ett gratis ActiveState Platform-konto, eller så kan du skapa ett eget). Utför sedan kommandot state activate för ditt givna 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 ställer kommandot activate in den virtuella miljön enligt definitionen i ditt ActiveState-projekt. I händelse av att projektet ännu inte har konfigurerats kommer ett enkelt projekt att sättas upp med standardparametrar för att ge dig ett exempel på hur allt ska gå ihop. Denna konfiguration lagras i en fil i roten av din projektkatalog som heter activestate.yaml.

Konfigurationsfil för hemligheter & Mer

Den activestate.yaml filen definierar en utvecklingskörtid under vilken ditt program kommer att köras. Standardfilen definierar till exempel ett enkelt skript som använder en hemlighet, samt några händelselistare som utför åtgärder när en definierad händelse inträffar:

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'"

Även om det inte finns något särskilt banbrytande här, borde den potentiella kraften i den här filen vara omedelbart uppenbar. Följande skript ger till exempel ett grundläggande exempel på hur man kan använda hemligheter 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 kommandot helloWorld exekveras (från ett aktiverat tillstånd) kommer det att eka värdet av user.world hemligheten och, i händelse av att hemligheten ännu inte är definierad, kommer det att fråga efter ett värde:

$ 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": ******

Användning av hemligheter

Och om exemplet är relativt förenklat så kommer det verkliga värdet av hemligheter från aktiveringshändelserna. Istället för att hämta ett hemligt värde inom ramen för ett skript kan miljövariabler definieras med hjälp av hämtade hemligheter utan att någonsin exponera dessa hemligheter utanför denna säkra 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}

Om hemligheten user.world är definierad kommer miljövariabeln WORLD att definieras och kan hämtas som vilken annan miljövariabel som helst:

$ echo $WORLDworld!

Om den däremot inte är definierad kommer användaren att uppmanas att definiera den vid aktivering av den virtuella ActiveState-miljön:

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": ******

Ganska coolt, eller hur?

För att gå vidare

Konfigurationshantering i programutveckling är för det mesta ett löst problem, men hantering av hemligheter är det inte ännu. Antalet projekt som har kontrollerat känsliga data i ett versionshanteringsarkiv är svindlande, och det är något som även högt respekterade företag har gjort, men genom användning av korrekt säkerhetshygien och produkter som ActiveState’s State Tool blir det lättare för varje dag att hålla känsliga konfigurationsdata säkra och skyddade.

  • Prova det själv genom att skapa ett gratis ActiveState Platform-konto och ladda ner State Tool för att förenkla hanteringen av hemligheter.
  • Du kan också titta på vårt webbseminarium om hur du hanterar delade hemligheter med State Tool

Relaterade bloggar:

Hemligheten med att hantera delade hemligheter

Utvecklare kan dela hemligheter snabbt och enkelt utan att offra säkerheten

.

Lämna ett svar

Din e-postadress kommer inte publiceras.