Winkelwagen

/ .nl-domeinnaam

Jouw .nl voor slechts € 0,49.

Domeinnaam checken
E-mail

/ Hostingpakket keuzehulp

Weet je niet zeker welk hostingpakket de beste
keus is voor jouw website? Met onze keuzehulp
kom je er wel uit.

Direct naar de keuzehulp

/ OpenStack

/ Probeer Public Cloud uit

Gratis 1 maand aan de slag met Public Cloud?

Vraag proefperiode aan

/ TransIP Blog

CSM25: API security in een SaaS-wereld

Lees de blogpost
Hulp nodig?

    Sorry, we konden geen resultaten vinden voor jouw zoekopdracht.

    Veilig met credentials omgaan in Linux

    Wanneer een script een wachtwoord, API key, token of private secret nodig heeft, is de onveiligste plek om het op te slaan direct in de source code. Hardcoded credentials lekken gemakkelijk via Git commits, backups, screenshots, logs, shell history en gekopieerde bestanden.

    Een secure setup op Linux volgt meestal één regel:

    sla het secret buiten het script op en injecteer het pas tijdens runtime.

    Dit artikel legt 10 van de veiligste veelgebruikte opties uit om credentials secure te gebruiken in Linux, wanneer je ze gebruikt en hoe je ze implementeert in Python.


     

    Waarom hardcoding van secrets gevaarlijk is

     

    Laten we kijken naar het gevaar van hardcoding van secrets aan de hand van een voorbeeld. Dit is wat je niet moet doen:

    DB_PASSWORD = "SuperSecretPassword123"

    Zelfs in een private repo kan dat wachtwoord terechtkomen in:

    • Git history
    • pull requests
    • code review tools
    • editor autosaves
    • backups
    • chat screenshots
    • logs als het per ongeluk wordt geprint
    • AI-conversaties als je je codebase blootstelt aan een LLM

    Zelfs als je het later verwijdert, kan Git de oude waarde nog steeds bevatten in eerdere commits.


     

    Algemene security-principes voor het omgaan met credentials

     

    Voordat we naar specifieke voorbeelden kijken, gelden deze principes overal:

    1. Houd secrets uit de source code: Je script moet alleen verwijzen naar een variabelenaam zoals DB_PASSWORD, niet naar het daadwerkelijke wachtwoord.
       
    2. Beperk toegang: Alleen de gebruiker of service account die het secret nodig heeft, mag het kunnen lezen.
       
    3. Geef secrets nooit mee op de command line: Vermijd commando's zoals: python3 app.py --password mysecret. Command-line arguments kunnen zichtbaar zijn in process listings en logs.
       
    4. Log secrets nooit: Print ze niet voor debugging en let erop dat je ze niet opneemt in exceptions.
       
    5. Geef waar mogelijk de voorkeur aan tokens boven wachtwoorden: Als een service API tokens, short-lived credentials of IAM-based access ondersteunt, zijn die vaak beter dan statische wachtwoorden.
       
    6. Roteer secrets: Zelfs goed beschermde secrets kunnen uiteindelijk uitlekken. Rotatie beperkt de schade.
       
    7. Gebruik gitignore: Als je bijvoorbeeld een .env-bestand gebruikt, voeg dit dan toe aan gitignore
       
    8. Laad wachtwoorden vanuit een environment variable of een beschermd bestand (minimaal)
       
    9. Bestandsrechten: stel bestandsrechten in op 600

     

    Welke optie moet je gebruiken?

     

    In dit artikel behandelen we 10 opties voor het secure omgaan met gevoelige credentials in Linux. Bij het gebruiken van deze opties helpen de algemene richtlijnen je om de beste optie te kiezen:

     

    Voor local development

    • Python keyring
    • .env-bestand buiten Git gehouden
    • Environment variable die interactief is ingesteld

     

    Voor een handmatig admin script

    • getpass
    • Python keyring

     

    Voor een server waarop een Linux service draait

    • Systemd credentials
    • Systemd met een beschermd environment-bestand

     

    Voor containers

    • Docker/Kubernetes secrets
    • Of de secret manager van je platform

     

    Voor serieuze productie-omgevingen

    • Een dedicated secret manager
    • Of... op zijn minst systemd credentials / mounted secret files

     

    Optie 1: Environment variables gebruiken

     

    Environment variables zijn een van de meest voorkomende benaderingen op Linux en houden het secret buiten je code.

     

    Voor-, nadelen & use cases van environment variables gebruiken

    Voordeel Nadeel Beste use case
    Simpel Environment variables kunnen zichtbaar zijn voor privileged users of via debugging tools local development
    breed ondersteund Ze kunnen lekken naar logs, crash dumps of child processes als je er niet zorgvuldig mee omgaat CI/CD
    gemakkelijk voor automation Ze zijn vaak prima, maar niet de sterkste optie voor high-security omgevingen containers
    houdt het secret buiten de source code  

    tijdelijke scriptuitvoering

     


     

    Python-voorbeeld

    import os
    
    def main():
        db_user = os.getenv("DB_USER", "appuser")
        db_host = os.getenv("DB_HOST", "localhost")
        db_password = os.getenv("DB_PASSWORD")
    
        if not db_password:
            raise RuntimeError("DB_PASSWORD is not set")
    
        print(f"Connecting to {db_host} as {db_user}")
        # connect_to_db(user=db_user, password=db_password, host=db_host)
    
    if __name__ == "__main__":
        main()

    Het wachtwoord wordt niet opgeslagen in het script. Het wordt tijdens runtime verwacht vanuit de environment.


     

    Veilige manieren om de variabele in te stellen

     

    Goed: interactief prompten

    read -s -p "DB_PASSWORD: " DB_PASSWORD; echo
    export DB_PASSWORD
    python3 app.py
    unset DB_PASSWORD

    Dit voorkomt dat het wachtwoord in de shell history terechtkomt.


     

    Riskanter: inline assignment

    DB_PASSWORD='mypassword' python3 app.py

    Dit is handig, maar niet ideaal op gedeelde systemen omdat het secret zichtbaar is in het shell-commando dat je hebt getypt en mogelijk wordt opgeslagen in de shell history.


     

    Optie 2: Beschermd bestand met strikte permissies

     

    Een andere goede Linux-native optie is om secrets op te slaan in een apart bestand dat alleen leesbaar is voor de juiste gebruiker. Dit is vaak beter dan secrets verspreiden over shell-profielen.

     

    Voor-, nadelen & use cases van beschermde bestanden met strikte permissies

    Voordelen Nadelen Use cases
    Zeer Linux-vriendelijk Het secret staat nog steeds als plaintext opgeslagen persoonlijke servers
    eenvoudig te beheren op servers Bestandsrechten moeten correct zijn eenvoudige automation
    werkt goed met backup- en permissiecontroles Gemakkelijk om per ongeluk onveilig te kopiëren of te back-uppen system accounts
        gecontroleerde VM-omgevingen

     

    Voorbeeld van een secret-bestand

     

    We kunnen bijvoorbeeld een secret-bestand hebben op deze locatie:

    ~/.config/myapp/secrets.env

    Het bestand kan de volgende inhoud hebben:

    DB_USER=appuser
    DB_HOST=localhost
    DB_PASSWORD=replace_me

    Om het bestand te beschermen met strikte permissies, kun je bijvoorbeeld permissies zoals deze instellen:

    mkdir -p ~/.config/myapp
    chmod 700 ~/.config/myapp
    chmod 600 ~/.config/myapp/secrets.env

    Dit betekent:

    • De directory is alleen toegankelijk voor jouw gebruiker
    • Het bestand is alleen leesbaar/schrijfbaar voor jouw gebruiker

     

    Python-voorbeeld dat het secret-bestand gebruikt

     

    Je kunt het secret-bestand laden vanuit de shell voordat je Python start, of het direct uitlezen.

     

    Methode A: source het in de shell

    set -a
    source ~/.config/myapp/secrets.env
    set +a
    python3 app.py

     

    Methode B: lees het bestand in Python uit

    from pathlib import Path
    
    def load_secrets_file(path):
        data = {}
        for line in Path(path).read_text().splitlines():
            line = line.strip()
            if not line or line.startswith("#"):
                continue
            key, value = line.split("=", 1)
            data[key.strip()] = value.strip()
        return data
    
    def main():
        secrets = load_secrets_file(Path.home() / ".config/myapp/secrets.env")
        db_password = secrets.get("DB_PASSWORD")
        db_user = secrets.get("DB_USER", "appuser")
        db_host = secrets.get("DB_HOST", "localhost")
    
        if not db_password:
            raise RuntimeError("DB_PASSWORD missing in secrets file")
    
        print(f"Connecting to {db_host} as {db_user}")
        # connect_to_db(user=db_user, password=db_password, host=db_host)
    
    if __name__ == "__main__":
        main()

     

    Optie 3: .env-bestand alleen voor development

     

    Een env-bestand is een veelgebruikt convenience-patroon voor developers. Het is prima voor development als je er zorgvuldig mee omgaat, maar het moet niet worden behandeld als een high-security production secret store.

     

    Voor-, nadelen & use cases van .env alleen voor development

    Voordelen Nadelen Use cases
    Zeer handig voor development Gemakkelijk per ongeluk te committen local development
    gebruikelijk ecosystem pattern Plaintext-bestand demo's
      Niet de beste keuze voor productie non-production setups

     

    Voorbeeld van een .env-bestand

    DB_USER=appuser
    DB_HOST=localhost
    DB_PASSWORD=replace_me

     

    Python-voorbeeld met python-dotenv

     

    Stap 1

    Installeer python-dotenv:

    pip install python-dotenv

     

    Stap 2

    Maak een script dat python-dotenv implementeert, bijvoorbeeld:

    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    def main():
        db_user = os.getenv("DB_USER", "appuser")
        db_host = os.getenv("DB_HOST", "localhost")
        db_password = os.getenv("DB_PASSWORD")
    
        if not db_password:
            raise RuntimeError("DB_PASSWORD is not set")
    
        print(f"Connecting to {db_host} as {db_user}")
        # connect_to_db(user=db_user, password=db_password, host=db_host)
    
    if __name__ == "__main__":
        main()

     

    Aanbevolen patroon

     

    Commit een template in plaats van een echt .env-bestand met secrets, bijvoorbeeld een bestand met de naam env.example met de volgende inhoud:

    DB_USER=appuser
    DB_HOST=localhost
    DB_PASSWORD=

    Daarna maakt elke developer zijn of haar eigen lokale env-bestand op basis van het voorbeeldbestand.


     

    Optie 4: Prompt tijdens runtime met getpass

     

    Als een persoon het script handmatig uitvoert, is de veiligste eenvoudige optie vaak om het wachtwoord helemaal niet op te slaan.

     

    Voor-, nadelen & use cases van prompten tijdens runtime met getpass

    Voordelen Nadelen Use cases
    Zeer eenvoudig Niet bruikbaar voor automation one-off scripts
    Niets opgeslagen at rest Bestaat nog steeds in het geheugen terwijl het proces draait admin tools
    Goed voor incidentele admin scripts   lokale handmatige taken

     

    Python-voorbeeld

    from getpass import getpass
    
    def main():
        db_user = "appuser"
        db_host = "localhost"
        db_password = getpass("Enter DB password: ")
    
        print(f"Connecting to {db_host} as {db_user}")
        # connect_to_db(user=db_user, password=db_password, host=db_host)
    
    if __name__ == "__main__":
        main()

    Het wachtwoord:

    • wordt niet getoond tijdens het typen
    • wordt niet opgeslagen in het script
    • hoeft niet op schijf te worden opgeslagen

     

    Optie 5: Linux desktop secret store via Python keyring

     

    Voor developer-laptops en workstations is een betere oplossing om de credential store van het OS te gebruiken. Op Linux kan Python’s keyring-library gebruikmaken van:

    • Secret Service API
    • GNOME Keyring
    • KWallet
    • andere ondersteunde backends

     

    Voor-, nadelen & use cases van een desktop secret store via Python keyring

    Voordelen Nadelen Use cases
    Beter dan plaintext-bestanden Kan lastiger zijn om op te zetten op headless servers Local development op Linux desktop
    Integreert met desktop security-mechanismen Backend-ondersteuning verschilt per omgeving Scripts op een persoonlijke workstation
    Eenvoudig voor lokale user workflows   Developer tooling

     

    Een Python keyring gebruiken

     

    Stap 1

    Installeer Python keyring:

    pip install keyring

     

    Stap 2

    Sla een wachtwoord eenmalig op:

    import keyring
    from getpass import getpass
    
    service_name = "myapp-db"
    username = "appuser"
    
    password = getpass("Enter DB password to store: ")
    keyring.set_password(service_name, username, password)
    
    print("Password stored securely.")

     

    Stap 3

    Haal het wachtwoord op dat in de keyring is opgeslagen in je app

    import keyring
    
    def main():
        service_name = "myapp-db"
        username = "appuser"
    
        db_password = keyring.get_password(service_name, username)
        if not db_password:
            raise RuntimeError("No password found in keyring")
    
        print("Password loaded from keyring")
        # connect_to_db(user=username, password=db_password, host="localhost")
    
    if __name__ == "__main__":
        main() 

     

    Optie 6: systemd service environment files

     

    Voor production Linux services is systemd vaak de juiste plek om secrets te injecteren. In plaats van het wachtwoord in het script op te slaan, zet je het in een beschermd bestand en laat je systemd het aan het proces leveren.

     

    Voor-, nadelen & use cases van een systemd service gebruiken

    Voordelen Nadelen Use cases
    Past bij standaard deployment van Linux services Secret bestaat nog steeds als plaintext op schijf VM-based production apps
    Houdt het secret buiten de code Vereist zorgvuldige permissies en ops hygiene background daemons
    Goede toegangscontrole via filesystem permissions   interne services op Linux

     

    Voorbeeldapplicatie met systemd service environment files

     

    Gebruik hetzelfde environment-based Python-script van eerder.

     

    Stap 1

    Maak een secret-bestand aan, bijvoorbeeld /etc/myapp/myapp.env, en geef het de volgende inhoud:

    DB_USER=appuser
    DB_HOST=localhost
    DB_PASSWORD=replace_me 

     

    Stap 2

    Pas de permissies van de directory en bestanden uit stap 1 aan, bijvoorbeeld: 

    sudo mkdir -p /etc/myapp
    sudo chown root:root /etc/myapp
    sudo chmod 755 /etc/myapp
    
    sudo chown root:myapp /etc/myapp/myapp.env
    sudo chmod 640 /etc/myapp/myapp.env  

    Het bestand is eigendom van root, maar leesbaar voor de myapp-groep.


     

    Stap 3

    Maak vervolgens een service unit file aan, bijvoorbeeld etc/systemd/system/myapp.service

    [Unit]
    Description=My Python App
    After=network.target
    
    [Service]
    User=myapp
    Group=myapp
    EnvironmentFile=/etc/myapp/myapp.env
    ExecStart=/usr/bin/python3 /opt/myapp/app.py
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target  

     

    Stap 4

    Start de service die je zojuist hebt aangemaakt:

    sudo systemctl daemon-reload
    sudo systemctl enable --now myapp.service  

     

    Optie 7: systemd credentials (veiliger dan gewone env-bestanden)

     

    Als je iets sterkers wilt dan een eenvoudig environment-bestand onder systemd (optie 6), dan is het credential-mechanisme het overwegen waard. Het vermijdt enkele nadelen van standaard environment variables.

    In plaats van secrets bloot te stellen als normale environment variables, wordt het secret tijdens runtime via credential files aan de service geleverd. Waarom is dit beter?

    • Het voorkomt normale blootstelling via environment variables
    • Schonere scheiding tussen app en secret source
    • Geschikter voor serieuze service deployments

    Het gebruik van systemd credentials is bedoeld voor meer security-bewuste deployments van Linux services en production services die door systemd worden beheerd. Afgezien daarvan gelden de meeste voor-, nadelen en use cases van het gebruik van een systemd service hier ook. 


     

    Voorbeeld van een service unit

    [Unit]
    Description=My Secure Python App
    After=network.target
    
    [Service]
    User=myapp
    Group=myapp
    LoadCredential=db_password:/etc/secretstore/db_password
    ExecStart=/usr/bin/python3 /opt/myapp/app.py
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target  

     

    Python-voorbeeld

    from pathlib import Path
    import os
    
    def get_systemd_credential(name: str) -> str:
        creds_dir = os.environ.get("CREDENTIALS_DIRECTORY")
        if not creds_dir:
            raise RuntimeError("CREDENTIALS_DIRECTORY not set")
        return (Path(creds_dir) / name).read_text().strip()
    
    def main():
        db_password = get_systemd_credential("db_password")
        print("Loaded password via systemd credentials")
        # connect_to_db(user="appuser", password=db_password, host="localhost")
    
    if __name__ == "__main__":
        main()  

     

    Optie 8: Docker secrets

     

    Als je app in containers draait, zijn environment variables gebruikelijk, maar Docker secrets zijn veiliger voor gevoelige waarden.

     

    Voor-, nadelen & use cases van Docker secrets gebruiken

    Voordelen Nadelen Use cases
    Beter dan secrets in images bakken Afhankelijk van de deployment setup Docker Swarm
    In veel gevallen beter dan gewone container env vars Local development gebruikt mogelijk nog steeds env of env vars Gecontaineriseerde Linux services
        Production container deployments

     

    Voorbeeld Python-code

    from pathlib import Path
    import os
    
    def get_secret():
        secret_file = os.getenv("DB_PASSWORD_FILE", "/run/secrets/db_password")
        return Path(secret_file).read_text().strip()
    
    def main():
        db_password = get_secret()
        print("Loaded password from Docker secret file")
        # connect_to_db(user="appuser", password=db_password, host="db")
    
    if __name__ == "__main__":
        main()  

    In plaats van DB_PASSWORD direct in te stellen, mount je een secret-bestand in de container.


     

    Optie 9: Kubernetes secrets

     

    Kubernetes Secrets zijn een standaardmanier om secrets aan workloads te leveren. Ze worden vaak als bestanden gemount of als env vars blootgesteld. Voor security hebben mounted files meestal de voorkeur boven environment variables.

     

    Python-voorbeeld

    from pathlib import Path
    
    def main():
        db_password = Path("/var/run/secrets/db_password").read_text().strip()
        print("Loaded password from mounted Kubernetes secret")
        # connect_to_db(user="appuser", password=db_password, host="db")
    
    if __name__ == "__main__":
        main()  

    Belangrijke opmerking: Kubernetes Secrets zijn niet automatisch "high security" alleen omdat ze secrets heten. Hun bescherming hangt af van:

    • etcd-encryptie
    • RBAC
    • pod security
    • clusterconfiguratie
     

     

    Optie 10: Cloud of externe secret managers

     

    Voor grotere of production-grade systemen zijn dedicated secret managers vaak de beste optie, bijvoorbeeld Google Secret Manager of HashiCorp Vault. Deze kunnen het volgende bieden:

    • Toegangscontrole
    • Auditing
    • Secret rotation
    • Tijdelijke credentials
    • Centraal beheer

    Dedicated secret managers zijn het meest geschikt voor:

    • Production infrastructure
    • Meerdere services
    • Gereguleerde omgevingen
    • Teams die auditability en rotation nodig hebben

     

    Generiek Python-patroon

    def get_secret_from_manager():
        # Placeholder for Vault / AWS / Azure / GCP SDK logic
        return "retrieved_secret"
    
    def main():
        db_password = get_secret_from_manager()
        print("Loaded password from external secret manager")
        # connect_to_db(user="appuser", password=db_password, host="db")
    
    if __name__ == "__main__":
        main()  

     

    Een goed gecombineerd Python-voorbeeld

     

    Deze versie ondersteunt meerdere secure bronnen in een logische volgorde:

    • environment variable
    • systemd credential
    • lokaal secret-bestand
    • interactieve prompt
    import os
    import sys
    from pathlib import Path
    from getpass import getpass
    
    def get_password() -> str:
        pw = os.getenv("DB_PASSWORD")
        if pw:
            return pw
    
        creds_dir = os.getenv("CREDENTIALS_DIRECTORY")
        if creds_dir:
            cred_file = Path(creds_dir) / "db_password"
            if cred_file.exists():
                return cred_file.read_text().strip()
    
        secret_file = Path.home() / ".config/myapp/db_password"
        if secret_file.exists():
            return secret_file.read_text().strip()
    
        if sys.stdin.isatty():
            return getpass("Enter DB password: ")
    
        raise RuntimeError("No password source available")
    
    def main():
        db_user = os.getenv("DB_USER", "appuser")
        db_host = os.getenv("DB_HOST", "localhost")
        db_password = get_password()
    
        print(f"Connecting to {db_host} as {db_user}")
        # connect_to_db(user=db_user, password=db_password, host=db_host)
    
    if __name__ == "__main__":
        main()  

    Dit houdt het wachtwoord buiten het script en maakt tegelijk secure setups mogelijk in verschillende omgevingen.


     

    Veelgemaakte fouten bij het omgaan met secure credentials

     

    • Secrets in Git zetten en vertrouwen op gitignore: gitignore helpt alleen voordat een bestand wordt gecommit. Zodra het is gecommit, staat het secret in de history.
       
    • Secrets opslaan in shell startup files: Productiewachtwoorden in bashrc of zshrc zetten is vaak rommelig en te breed. Deze bestanden worden geladen voor veel shell-sessies en kunnen terechtkomen in backups of support bundles.
       
    • World-readable bestanden gebruiken: Een secret-bestand met 644-permissies is geen secret-bestand. Gebruik: chmod 600 secretfile  
       
    • Configuratie-dictionaries printen: Dit kan per ongeluk waarden zoals wachtwoorden en API keys blootstellen.
       
    • Overal hetzelfde wachtwoord hergebruiken: Als één systeem lekt, worden alle andere ook geraakt.

    Kom je er niet uit?

    Ontvang persoonlijke hulp van onze supporters

    Neem contact op