Loading search data...

Devops - Gérer finement vos secrets avec Mozilla SOPS

Publié le : 26 décembre 2022 | Mis à jour le : 26 décembre 2022

logo devops

Pour rappel, un secret est une information qui est utilisée pour accéder à certaines ressources, comme des bases de données, des apis, etc et qui ne doit pas être rendue publique pour des raisons évidentes de sécurité. Donc si vous développez du code d’Infrastructure (IaC) vous devez absolument éviter de les divulguer en les possant dans les dépôts de source de code ! Mais alors comment les stocker ?

Comment stocker vos secrets ?

La première solution est d’utiliser un utilitaire qui va se charger de chiffrer et de déchiffrer ces données sensibles. Pour le code Ansible, nous avons à notre disposition ansible-vault. Mais ses fonctionnalités sont très limitées. Ansible-vault n’utilise qu’une seule clé pour chiffrer un fichier Alors comment gérer finement les droits d’accès ?

La seconde solution est de recourir à une application tierce spécialisée pour gérer vos secrets, comme HashiCorp Vault. Mais cela demande pas mal de ressources pour sa mise en place et sa maintenance. Et parfois, nous aimerions tout de même conserver nos fichiers de configuration dans le code source. Mais alors comment les protéger ?

C’est pour répondre à ces problématiques que les ingénieurs de Mozilla ont conçues SOPS.

Qu’est-ce que SOPS

SOPS pour Secrets OPerationS, est une CLI qui permet de chiffrer des fichiers textes ou binaires. Il permet d’éditer directement les fichiers de configuration aux formats : YAML, JSON, ENV et INI. SOPS automatise en fait le déchiffrage à l’ouverture et le chiffrage à la sauvegarde de ces fichiers. Autre particularité, pour ces fichiers textes SOPS ne chiffre que les valeurs et non les clés, ce qui permet d’en garder la structure, bien utile pour les manipuler sans les déchiffrer. Pour chiffrer les données, SOPS peut utiliser des clés PGP, AGE, HashiCorp Vault, AWS KMS, GCP KMS, et Azure Key Vault.

Installations de Mozilla SOPS

SOPS fonctionne sur les principaux systèmes d’exploitation que sont Linux, Windows et MacOS. Toutes les exécutables sont disponibles dans les releases du dépot officiel.

Installation de SOPS sur MacOS

Rien de plus simple :

brew install sops

Installation de SOPS sur un poste Windows

Télécharger le binaire sops-vx.x.x.exe . Renommer le fichier en sops.exe et déplacer le dans un répertoire défini dans la variable PATH ou plus simplement dans le répertoire C:\Windows\System32.

Installation de SOPS sur une distribution Linux

Vous avez deux solutions pour installer SOPS sur Linux :

wget https://github.com/mozilla/sops/releases/download/v3.7.3/sops_3.7.3_amd64.deb
sudo dpkg -i sops_3.7.3_amd64.deb
asdf plugin add asdf
asdf install sops latest
asdf global sops latest
sops -- version
sops 3.7.3 (latest)

Utilisation de SOPS

Maintenant que SOPS est installé voyons comment l’utiliser pour sécuriser vos secrets dans vos dépôts de code source.

Chiffrer des fichiers avec SOPS

Chiffrer des fichiers avec une clé AGE

Si vous n’utilisez pas de cloud Public, vous pouvez utiliser des clés PGP ou Age pour chiffrer vos secrets. Si vous voulez partager vos secrets à plusieurs personnes, la solution la plus simple est de les stocker dans un gestionnaire de mots de passe comme bitwarden, LastPass, …

Attention le support de PGP pourrait disparaitre dans les prochaines versions de SOPS (cf issue)

Nous ne verrons donc que l’utilisation d'AGE pour chiffrer vos secrets. Commençons par l’installer sur notre poste de travail Ubuntu, pour les autres systèmes d’exploitation, c’est par .

sudo apt install age

Ensuite créons notre première clé PGP :

mkdir -p ~/keys

age-keygen -o ~/keys/ma-premiere-cle-age.txt

Public key: age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq

Pour notre exemple, nous allons utiliser le fichier test.yaml avec ce contenu

username: test
password: toto

A présent chiffrons notre fichier avec la CLI sops.

sops -e --age=age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq test.yaml > test-enc.yml

Voici le contenu du fichier généré :

username: ENC[AES256_GCM,data:cEM0zQ==,iv:BzqgugnPJrlDfkjvnplyPglMSxFAQpnJBYTf2BWnBoE=,tag:33X7yZ+J8uB6X60EJx8RzQ==,type:str]
password: ENC[AES256_GCM,data:I5fssg==,iv:IQjy76Wwj7/t8K1EtqPPgrpd9KIZbEhErnAGoMLMsdg=,tag:EinjQGuhrDLafM2Mf9mitg==,type:str]
sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    hc_vault: []
    age:
        - recipient: age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmKzE4MlpMNTZUR0JUT2pH
            VE9TM3p2ekhoYUJwM2hNZzJHaTNWVE10aVJFCkFXYUF2Zyt6WEtsN29seTRCTk5i
            NVIwWWxZaGxudjlXRmxDMWh1a1pmMzgKLS0tIEtpNi9xRHZ5bGgybVVUQnBmNFNR
            aWd2bFp2Mk1zb3c2WXB2SGZZN0xFNXcKN0mpn+vbo8R7VpTjuKLmmSh0letc4zzd
            TvNiI1G0PtCZ94ZvtXvOx9m36gqDkbCmIXsADRU5Ay7LoJP49CoIOQ==
            -----END AGE ENCRYPTED FILE-----            
    lastmodified: "2022-12-26T10:08:45Z"
    mac: ENC[AES256_GCM,data:Y7IZLnSdst04Xa2Hga+JhWyK9fnBW+16TpT9II/ehQOCEuHqfZ65xMjQZLm9dnUWohPZV8XKEnh6crIvfHk/RQbiFm5QY/6acEgxsk8Gp7eqbcExmazipcc9iGJB2jAgDS0bRMz6H/xbsITQYeueuL200IfJkjjtbRtpNU5PXWo=,iv:e45jTNmuDdakgP7UTR/8FJxPSmk2iNdAdc7VCEaU61w=,tag:RMrrQtYWoDhZqVSjsv1c6Q==,type:str]
    pgp: []
    unencrypted_suffix: _unencrypted
    version: 3.7.3

Nous voyons que la structure du fichier est bien conservée et que seules les valeurs sont chiffrées.

Chiffrer des fichiers avec AWS KMS

La CLI AWS doit être installé en premier. Ensuite, il suffit de créer la clé KMS :

export AWS_PROFILE=perso
export AWS_DEFAULT_REGION=eu-west-3
aws kms create-key --tags TagKey=Purpose,TagValue=Test --description "Ma première clé KMS"

{
    "KeyMetadata": {
        "AWSAccountId": "276757567417",
        "KeyId": "1ff319fe-cb40-4738-9335-a85c28a2f159",
        "Arn": "arn:aws:kms:eu-west-3:276757567417:key/1ff319fe-cb40-4738-9335-a85c28a2f159",
        "CreationDate": "2022-12-26T11:32:56.466000+01:00",
        "Enabled": true,
        "Description": "Ma première clé KMS",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "Origin": "AWS_KMS",
        "KeyManager": "CUSTOMER",
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "KeySpec": "SYMMETRIC_DEFAULT",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ],
        "MultiRegion": false
    }
}

Ensuite, nous pouvons chiffrer le fichier :

sops -e --kms arn:aws:kms:eu-west-3:276757567417:key/1ff319fe-cb40-4738-9335-a85c28a2f159 test.yaml > test-enc.yml

Utiliser plusieurs clés dans SOPS

Dans certains cas, vous aimeriez définir une clé par utilisateur pour définir plus finement les accès aux secrets. Commençons par créer une seconde clé :

age-keygen -o ~/keys/ma-second-cle-age.txt

Public key: age1afht98nlh0cmw4recumvw5g4ny72edwz8sp360qzxqsrputfny5smcy2rd

Pour chiffrer le fichier ainsi, il suffit de lancer la même commande que précédemment en séparant les clés par une virgule.

sops -e --age=age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq,age1afht98nlh0cmw4recumvw5g4ny72edwz8sp360qzxqsrputfny5smcy2rd test.yaml > test-enc.yaml

Le contenu du fichier :

username: ENC[AES256_GCM,data:cXaMaw==,iv:1PH3oXYheej1Wyowa5eaxYmZvtYLXGCrMn8cQyEvew0=,tag:Yae59rLccwKssBAZJvbuXw==,type:str]
password: ENC[AES256_GCM,data:iYVYuQ==,iv:UlMyvevl82dnRmhbiAYbi6/DWiWbdj1T+o5sk3+LK94=,tag:lNqCNLnY1QUKdLgY9EyEMQ==,type:str]
sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    hc_vault: []
    age:
        - recipient: age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXaUZyRndEcG8rSmhQd3FH
            QVZhdGlYaFNCOXF3NEV4cExrVXkwYWg3UG5nCjhyWHM2L0lxRjJvaGgwRFdWN1pS
            aEhPaVNzUFdFWWNlMzc5SWhGYlg1NU0KLS0tIHNkTERRYXh1R1Y4VDZtTTRGRm50
            R1h4ZGNCbjJ2aUFDT2sydFhYQ0ZCN2cK4rmbrwK6tAMq6YvgJeBvn7fnF/8+la0A
            a852VWFWusKnTx01E+UwXRuz2dxAyPWkuMLgCvz9LSFc9kWykdkNcw==
            -----END AGE ENCRYPTED FILE-----            
        - recipient: age1afht98nlh0cmw4recumvw5g4ny72edwz8sp360qzxqsrputfny5smcy2rd
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJRzlOVGlONE5LaHpKMElH
            SHdSODltNHFNdW9nMFY0L1U0S2NremZCZEFRCktBdUg5Q1ZWTEhlRWY4MUJEa3RF
            NWpzVElOVDdNWjZsUXpqbVh6S3VGaGcKLS0tIE12RmJCUks0LzUwUU9Yckpzb1hL
            ZGg5VEdHL3cva0I4eVpwTHhhdEh3RzgKkhIkjujnGHpSezJEWcFkxm0dt15tndZJ
            x1C9XMaxrHqNcDMSGxpSVPSByTMVyy+Drh3j9PvgsBOsQLrrGXtHUw==
            -----END AGE ENCRYPTED FILE-----            
    lastmodified: "2022-12-26T10:15:48Z"
    mac: ENC[AES256_GCM,data:fqtzM3ezbTI7gv7EvKZsSLy1GwcXrVFw5BRiCkzEfwOatvZeZL2jma5Yg3UGgL0u9Dm5A0LVq+5ZpAvcUvfHDGcOK0gPJ1klvXHRnuMmFgUd7WCzlfS4iLHxx5j8KiL2otcyn0KEkjhIfiEjyW/ajm2A2QIR/z4JRvjSbzleVG0=,iv:lqJRx+v0KKHkodqagqnNRjrhvpY3OZ3rk+3zrmj1ooU=,tag:VxFVvuvyLmYdBA25aWtTpQ==,type:str]
    pgp: []
    unencrypted_suffix: _unencrypted
    version: 3.7.3

On retrouve bien les deux clés.

Vous pouvez aussi utiliser deux systèmes de chiffrement :

sops -e --kms arn:aws:kms:eu-west-3:276757567417:key/1ff319fe-cb40-4738-9335-a85c28a2f159 --age=age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq test.yaml > test-enc.yaml

Déchiffrer des fichiers avec SOPS

Il suffit d’utiliser la commande --decrypt ou -d :

sops -d test-enc.yaml
Failed to get the data key required to decrypt the SOPS file.

Group 0: FAILED
  age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq: FAILED
    - | failed to open file: open
      | /home/vagrant/.config/sops/age/keys.txt: no such file or
      | directory

  age1afht98nlh0cmw4recumvw5g4ny72edwz8sp360qzxqsrputfny5smcy2rd: FAILED
    - | failed to open file: open
      | /home/vagrant/.config/sops/age/keys.txt: no such file or
      | directory

Recovery failed because no master key was able to decrypt the file. In
order for SOPS to recover the file, at least one key has to be successful,
but none were.

Si on lance la commande directement sans indiquer le chemin des clés privées, nous obtenons bien un échec. Pour indiquer le chemin avec la variable suivante :

export SOPS_AGE_KEY_FILE=~/keys/ma-second-cle-age.txt

sops -d test-enc.yaml
username: test
password: toto

Configuration de SOPS

Plutôt que de lancer les commandes avec toutes les options, il est possible de définir la configuration SOPS, dans un fichier. Le nom du fichier par défaut est : .sops.yaml.

creation_rules:
    - path_regex: test.*\.yaml
      key_groups:
      # First key group
      - age:
        - age1upjug3ygl55vswr4wjewuunnr4z74ptfygkgfj44sm0u454egqsqdkdxqq
        kms:
        - arn: arn:aws:kms:eu-west-3:276757567417:key/1ff319fe-cb40-4738-9335-a85c28a2f159

SOPS et Ansible

Pour déchiffrer les fichiers produits avec SOPS dans les playbooks Ansible, il suffit d’installer la collection suivante :

ansible-galaxy collection install community.sops

Et de faire appel à son lookup :

---
- name: Decrpyt SOPS
  hosts: all
  gather_facts: false
  tasks:
    - name: Read file
      ansible.builtin.debug:
        msg: "{{ lookup('community.sops.sops', 'test-enc.yaml') }}"

On lance le playbook :

ansible-playbook -i localhost, -c local test-playbook.yml
localhost | SUCCESS => {
    "msg": "username: test\npassword: toto"
}

Conclusion

Comme vous avez pu le voir SOPS est un outil qui peut parfaitement d’intégrer dans un pipeline CI/CD. Couplé avec un gestionnaire de mots de passe ou de clés, il offre un bon moyen de stocker dans un dépôt git des données sensibles, et cela, en toute sécurité. Donc fini les multiples secrets stockés dans les configurations de Github et GitLab.

Mots clés :

devops tutorials

Si vous avez apprécié cet article de blog, vous pouvez m'encourager à produire plus de contenu en m'offrant un café sur  Ko-Fi. Vous pouvez aussi passer votre prochaine commande sur amazon, sans que cela ne vous coûte plus cher, via  ce lien . Vous pouvez aussi partager le lien sur twitter ou Linkedin via les boutons ci-dessous. Je vous remercie pour votre soutien.

Autres Articles


Commentaires: