Skip to content

    Secret references

    A plan carries a pointer to a secret, never the secret. That is what makes a plan safe to read, review, and keep in git.

    Opafra never stores a secret inside a plan. A plan carries a reference, resolved at the moment of use, and the value goes to the host without ever being written into the plan, the run log, or a preview.

    a reference, not a password
    - name: Rotate the app database password
      tool: ssh.cmd
      args:
        command: "mysql -u root -p'secret://vault/prod/mysql_root' -e 'FLUSH PRIVILEGES'"

    The shape of a reference#

    secret://<provider>/<namespace>/<key>

    The provider is where the secret lives, the namespace scopes it within that provider, and the key names it. A second scheme exists for values supplied by the infrastructure Opafra runs on:

    env:VAR_NAME

    Use env: for a credential the deployment provides, and secret:// for everything a team manages.

    Why a reference rather than encryption#

    Encrypting a secret in the plan still puts the secret in the plan. Every copy of that plan, every export, every backup, and every screen showing it then contains the material, protected by a key that also has to live somewhere.

    A reference is different in kind. It is not sensitive, so a plan holding one can be:

    • Read by anyone reviewing the automation, including people who should never see the credential itself
    • Kept in git, diffed in a pull request, and reviewed like code
    • Copied between environments, where the same reference resolves to that environment's own value
    • Shown in a dry run to an approver, who sees exactly what would run without being handed a password

    That last point is the one that matters most in practice. Review and secrecy stop being in tension.

    Where a reference can be used#

    Anywhere a value is expected: a tool argument, a command, an environment variable, a server credential.

    An environment variable can be marked secret, in which case its value is stored as a reference too. So {{ vars.db_password }} in a plan resolves through the environment to the provider, and the plan names neither the secret nor the provider.

    Redaction#

    References are redacted everywhere a command or value is displayed: in a dry-run preview, in the live run console, in the stored run record, and in stderr captured from a failed connection.

    Redaction over-matches on purpose. Any argument whose name looks like a credential is masked as well, and the same masking runs over rendered config file contents in a diff. Hiding something that was not a secret is a smaller problem than printing one that was.

    Tenant boundaries#

    A reference resolves only within its own tenant's namespace. A hand-crafted reference pointing at another organisation's namespace is rejected rather than followed, so a reference is not a way to probe or reach across a boundary.

    What is stored#

    The reference. Server credentials are held either as a reference to your provider or encrypted at rest when Opafra holds them itself, and neither form appears in an API response, a plan, or a log.

    A generated SSH private key is the strongest case: it is shown once, when created, and no endpoint returns it a second time.

    Next steps#