Skip to content

sops_encrypt: support DotEnv or INI store #262

@alteriks

Description

@alteriks
SUMMARY

When using community.sops.sops_encrypt with content_text: module assumes --input-type=json/--output-type=json. There are no options to override this like in community.sops.decrypt

ISSUE TYPE
  • Bug Report
COMPONENT NAME

community.sops.sops_encrypt

ANSIBLE VERSION
ansible [core 2.17.4]
  config file = /home/alteriks/git/acs/ansible.cfg
  configured module search path = ['/home/alteriks/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/alteriks/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/alteriks/git/acs/galaxy
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Feb  4 2025, 14:57:36) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True
COLLECTION VERSION

# /home/alteriks/.local/lib/python3.10/site-packages/ansible_collections
Collection     Version
-------------- -------
community.sops 1.9.0  

# /home/alteriks/git/acs/galaxy/ansible_collections
Collection     Version
-------------- -------
community.sops 2.2.1  
CONFIGURATION
CACHE_PLUGIN(/home/alteriks/git/acs/ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/home/alteriks/git/acs/ansible.cfg) = ansible_fact_cache
CALLBACKS_ENABLED(/home/alteriks/git/acs/ansible.cfg) = ['auto_tags']
COLLECTIONS_PATHS(/home/alteriks/git/acs/ansible.cfg) = ['/home/alteriks/git/acs/galaxy']
CONFIG_FILE() = /home/alteriks/git/acs/ansible.cfg
DEFAULT_ACTION_PLUGIN_PATH(/home/alteriks/git/acs/ansible.cfg) = ['/home/alteriks/.local/lib/python3.10/site-packages/ara/plugins/action']
DEFAULT_CALLBACK_PLUGIN_PATH(/home/alteriks/git/acs/ansible.cfg) = ['/home/alteriks/git/acs/plugins/callbacks']
DEFAULT_FORKS(/home/alteriks/git/acs/ansible.cfg) = 20
DEFAULT_HOST_LIST(/home/alteriks/git/acs/ansible.cfg) = ['/home/alteriks/git/acs/hosts']
DEFAULT_LOAD_CALLBACK_PLUGINS(/home/alteriks/git/acs/ansible.cfg) = True
DEFAULT_ROLES_PATH(/home/alteriks/git/acs/ansible.cfg) = ['/home/alteriks/git/acs/galaxy/roles', '/home/alteriks/git/acs/roles']
DEFAULT_STDOUT_CALLBACK(/home/alteriks/git/acs/ansible.cfg) = yaml
DISPLAY_SKIPPED_HOSTS(/home/alteriks/git/acs/ansible.cfg) = False
EDITOR(env: EDITOR) = nvim
HOST_KEY_CHECKING(/home/alteriks/git/acs/ansible.cfg) = False
INTERPRETER_PYTHON(/home/alteriks/git/acs/ansible.cfg) = auto
PAGER(env: PAGER) = less -r
RETRY_FILES_ENABLED(/home/alteriks/git/acs/ansible.cfg) = False
STEPS TO REPRODUCE

Create dotenv style sops file:

export SOPS_AGE_KEY=AGE-SECRET-KEY-1VX24NQPMSKZWHY4EKKNYW94VMTDHWDTWWWUWR4PE5SU7CPUSJF8QA9C9GZ 
sops edit --output-type=dotenv --input-type=dotenv env.sops
DB_PASSWORD=__SUPER_SECRET_PASSWORD__

Verify:

cat  env.sops
DB_PASSWORD=ENC[AES256_GCM,data:W1XWpILkMY/CiyIU5+EBU3YPZ9/HJ9jzgw==,iv:Zr4w/5eMwcHlo0RcEG7dnhGYVa0F5+izPngf35GkXMU=,tag:PtIprzdHmEU1KzHmMWu76Q==,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZL0U0cW1CNlZiZzh1SVEx\nZlQrT2owYXJXdjVvOU04MnpZVDlXNS92M1Y0ClMyMzk0UDlUNlZRRlRQNXU3MFZx\nZElWejI0c3A5bXpoVCtJYnhWeE9WLzAKLS0tIHg5UHlLZW1xaWdiUjFZSG9FbzQ2\nbFlqNExBOUJ4cjNWM0JEdFRlaVFUbU0KcJsoJbQNojxnH7VYyGMFBE/PH0yanw/4\noJp6N70cKi+Gh7AMv7S19mzHl+og0Dq2te+E3cV6gH3sV1q8k8GKhQ==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1czcar7h6ll9dz8n9uquzqaxvvesd37f9x36mnnrsj77c7xqldgcqhljg7a
sops_lastmodified=2025-08-18T11:49:40Z
sops_mac=ENC[AES256_GCM,data:OMhXXhTR7A/LF64yeOim6JYV0UVtIEuh1JjScYnT7JlVBOcneg/uSMxH4S6mKrxPtMf4Eij7Ly5lxZN3C1aUsvJMDnTe1OwbZQ+xena5QqrC2iSYiZFFcHFf3SXQd90wu/stxU5kV6x5bva6OnnRqqYEhc255wMpPnP1wHj7wWE=,iv:vp2GgveS61/Ki4uWLv/Gx6UwEN6neTu6ndn1gCeXK4Q=,tag:6oIYOdD7xeEisAj9J7AHcw==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.10.2
    - name: Update env file with new password SOPS
      community.sops.sops_encrypt:
        path: "/tmp/pgsql-pwchange/env.sops"
        age_key: 'AGE-SECRET-KEY-1VX24NQPMSKZWHY4EKKNYW94VMTDHWDTWWWUWR4PE5SU7CPUSJF8QA9C9GZ'
        config_path: "/tmp/pgsql-pwchange/.sops.yaml"
        content_text: "DB_PASSWORD=__ANOTHER_SUPER_SECRET_PASSWORD__"
EXPECTED RESULTS

Module should recognize dotenv style files just like it does with yaml

export SOPS_AGE_KEY=AGE-SECRET-KEY-1VX24NQPMSKZWHY4EKKNYW94VMTDHWDTWWWUWR4PE5SU7CPUSJF8QA9C9GZ 
sops edit env.sops.yaml
DB_PASSWORD: __SUPER_SECRET_PASSWORD__

Verify:

cat env.sops.yaml
DB_PASSWORD: ENC[AES256_GCM,data:Mwvzx2JTQ4YUl5QECPFmeskwcyPoRILTGw==,iv:HFEy4a/0fBhl9KQM7yTV9IEyLfQmIQ/IQ0QqInWPzUQ=,tag:h6Xt429/H0e1i53FKUihDw==,type:str]
sops:
    age:
        - recipient: age1czcar7h6ll9dz8n9uquzqaxvvesd37f9x36mnnrsj77c7xqldgcqhljg7a
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqa2tNQXJ3dGFOeHhEeTg4
            a3cwczFJeHFKejI0VStteFdOcmo2RVJ6TkUwCkpaVnVmeUQxUTEwVGd1NGJJRWxP
            VmNBT0ZCNjVHRzBZRHNWVXBvVnBWREEKLS0tICtlNGlHTllZT2NYRTJhSGhPL2lu
            bjRwUHNDemYxdzIyM1FtUVJBZk0vZzQKSUCV6hAtYEQDNWKocR/f2JGK+G/oN10F
            hpHCPmoVlJNxZB5pKpC7E55ncsZLIAC02cvzhukEANGBL4n57hXjzg==
            -----END AGE ENCRYPTED FILE-----
    lastmodified: "2025-08-18T11:57:18Z"
    mac: ENC[AES256_GCM,data:7FMaU05QQTQnLERPczWdtm0FRrsDyhesvwQgepapQqjIxqM9OzsQTe3cnSYdN/mrVgFGHpMTqTG2RIjO+0l7K0Ij0cWY83OmSjSdWz57S4x8ry3GtZyEoSBxwO9H1pn5u0J9II1elTh2QS3RjNFtL6pN5GUfAON57ICT9FO3hL0=,iv:2shWYu5wnQXWrisIOFT/lSH0inyKUTXpw1wAtbumr3w=,tag:aNKeOazXpx5oRVKcWj4aJw==,type:str]
    unencrypted_suffix: _unencrypted
    version: 3.10.2

Use following playbook:

    - name: Update env file with new password SOPS
      community.sops.sops_encrypt:
        age_key: 'AGE-SECRET-KEY-1VX24NQPMSKZWHY4EKKNYW94VMTDHWDTWWWUWR4PE5SU7CPUSJF8QA9C9GZ'
        path: "/tmp/pgsql-pwchange/env.sops.yaml"
        config_path: "/tmp/pgsql-pwchange/.sops.yaml"
        content_yaml:
          DB_PASSWORD: "__ANOTHER_SUPER_SECRET_PASSWORD__"

Run:

TASK [Update env file with new password SOPS] *******************************************************************************
task path: /home/alteriks/git/acs/playbooks/99_tmp_update_pgsql_password.yml:108
changed: [localhost] => changed=true 
  invocation:
    module_args:
      age: null
      age_key: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
      age_keyfile: null
      age_ssh_private_keyfile: null
      attributes: null
      aws_access_key_id: null
      aws_profile: null
      aws_secret_access_key: null
      aws_session_token: null
      azure_kv: null
      config_path: /tmp/pgsql-pwchange/.sops.yaml
      content_binary: null
      content_json: null
      content_text: null
      content_yaml:
        DB_PASSWORD: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
      enable_local_keyservice: false
      encrypted_regex: null
      encrypted_suffix: null
      encryption_context: null
      force: false
      gcp_kms: null
      group: null
      hc_vault_transit: null
      keyservice: null
      kms: null
      mode: null
      owner: null
      path: /tmp/pgsql-pwchange/env.sops.yaml
      pgp: null
      selevel: null
      serole: null
      setype: null
      seuser: null
      shamir_secret_sharing_threshold: null
      sops_binary: null
      unencrypted_regex: null
      unencrypted_suffix: null
      unsafe_writes: false
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: alteriks
<127.0.0.1> EXEC /bin/sh -c 'echo ~alteriks && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/alteriks/.ansible/tmp `"&& mkdir "` echo /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226 `" && echo ansible-tmp-1755518896.3501678-2975206-57639295463226="` echo /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226 `" ) && sleep 0'
Using module file /home/alteriks/git/acs/galaxy/ansible_collections/lvrfrc87/git_acp/plugins/modules/git_acp.py
<127.0.0.1> PUT /home/alteriks/.ansible/tmp/ansible-local-2974870g3cbni9i/tmpj1eeliqk TO /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226/AnsiballZ_git_acp.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226/ /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226/AnsiballZ_git_acp.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'GIT_AUTHOR_NAME=ansible-bot [email protected] GIT_COMMITTER_NAME=ansible-bot [email protected] /usr/bin/python3 /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226/AnsiballZ_git_acp.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/alteriks/.ansible/tmp/ansible-tmp-1755518896.3501678-2975206-57639295463226/ > /dev/null 2>&1 && sleep 0'

Verify after:

export SOPS_AGE_KEY=AGE-SECRET-KEY-1VX24NQPMSKZWHY4EKKNYW94VMTDHWDTWWWUWR4PE5SU7CPUSJF8QA9C9GZ 
sops decrypt /tmp/pgsql-pwchange/env.sops.yaml
DB_PASSWORD: __ANOTHER_SUPER_SECRET_PASSWORD__
ACTUAL RESULTS

Encrypting env.sops using first playbook gives following error:

TASK [Update env file with new password SOPS] *******************************************************************************
task path: /home/alteriks/git/acs/playbooks/99_tmp_update_pgsql_password.yml:108
The full traceback is:
  File "/tmp/ansible_community.sops.sops_encrypt_payload_4nrvs7q1/ansible_community.sops.sops_encrypt_payload.zip/ansible_collections/community/sops/plugins/modules/sops_encrypt.py", line 209, in main
  File "/tmp/ansible_community.sops.sops_encrypt_payload_4nrvs7q1/ansible_community.sops.sops_encrypt_payload.zip/ansible_collections/community/sops/plugins/module_utils/sops.py", line 324, in decrypt
    return runner.decrypt(
  File "/tmp/ansible_community.sops.sops_encrypt_payload_4nrvs7q1/ansible_community.sops.sops_encrypt_payload.zip/ansible_collections/community/sops/plugins/module_utils/sops.py", line 229, in decrypt
    raise SopsError(encrypted_file, exit_code, err, decryption=True)
fatal: [localhost]: FAILED! => changed=false 
  invocation:
    module_args:
      age: null
      age_key: null
      age_keyfile: null
      age_ssh_private_keyfile: null
      attributes: null
      aws_access_key_id: null
      aws_profile: null
      aws_secret_access_key: null
      aws_session_token: null
      azure_kv: null
      config_path: /tmp/pgsql-pwchange/.sops.yaml
      content_binary: null
      content_json: null
      content_text: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
      content_yaml: null
      enable_local_keyservice: false
      encrypted_regex: null
      encrypted_suffix: null
      encryption_context: null
      force: false
      gcp_kms: null
      group: null
      hc_vault_transit: null
      keyservice: null
      kms: null
      mode: null
      owner: null
      path: /tmp/pgsql-pwchange/env.sops
      pgp: null
      selevel: null
      serole: null
      setype: null
      seuser: null
      shamir_secret_sharing_threshold: null
      sops_binary: null
      unencrypted_regex: null
      unencrypted_suffix: null
      unsafe_writes: false
  msg: |-
    error with file /tmp/pgsql-pwchange/env.sops: ErrorGeneric exited with code 1: Error unmarshalling input json: invalid character 'D' looking for beginning of value

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions