Skip to content

secrets

Jesús Daniel Colmenares Oviedo edited this page Jun 18, 2026 · 1 revision

Working with Secrets

Just like any other tool that prefer code and operates declaratively, there comes a time when you need to use a file that no one but the authorized person should know about. Overlord doesn’t have the concept of "secrets," but that doesn’t mean it can’t be used with tools like SOPS.

In tools with the approach described above, such as Overlord, this means there are two ways to use secrets: in a dotenv file that Overlord loads every time it's executed, and from a YAML file (a deployment file).

In this tutorial, we’ll deploy www/freenginx with a self-signed TLS certificate and a key to demonstrate how to use Overlord with SOPS. Let’s start by initializing our git(1) repository, where the files will be tracked.

$ git init secrets
Initialized empty Git repository in /tmp/secrets/.git/
$ cd secrets/

We need to decide which backend to use. The simplest yet secure option is Age, which can be installed using security/rage-encryption.

$ mkdir -p ~/.config/sops/age
$ rage-keygen > ~/.config/sops/age/keys.txt

Configure your .sops.yaml file and put Age's public key.

.sops.yaml:

creation_rules:
  - age: >-
      age1mazpcdhuz4rqjd3u5p7lt2ns7kzwveaafas6pg5dcnt0lf5x4ejqaq3jgf

Now is the time to create our dotenv file.

$ sops edit .enc.env

And add the following:

ENTRYPOINT=http://100.65.139.52:8888
TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXRhZGF0YSI6eyJvdmVybG9yZC52ZXJzaW9uIjoiMC4yNS4wIn0sInJhbmRvbV9jaHVuayI6IjJlZWIzNjI0MWZmMGIxZTUiLCJleHAiOjE3ODE4MjIzMTF9.tc0sh6vDeF9i9mHMeNxGsouVnDlLmc5d4iO-LkPeklc

Where ENTRYPOINT is the URL for connecting to an Overlord instance. Overlord can use multiple entry points at the same time, but typically only one is used; in this case, an entry point would not be considered a secret, but it is useful to include it in our dotenv file if we are going to have many deployment files. The second environment variable is TOKEN, which must be kept secret and corresponds to an access token generated by the ENTRYPOINT instance. For example:

# OVERLORD_CONFIG=/tmp/overlord.yml overlord gen-token --expire 1 --expire-type hours
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXRhZGF0YSI6eyJvdmVybG9yZC52ZXJzaW9uIjoiMC4yNS4wIn0sInJhbmRvbV9jaHVuayI6IjJlZWIzNjI0MWZmMGIxZTUiLCJleHAiOjE3ODE4MjIzMTF9.tc0sh6vDeF9i9mHMeNxGsouVnDlLmc5d4iO-LkPeklc

The file above is the encrypted dotenv file, but the tools use a plaintext dotenv file.

$ sops decrypt .enc.env > .env

Remember to tell git(1) that our dotenv file should not be tracked.

$ echo ".env" >> .gitignore

Let's create a simple, readOnly deployment to check if everything is ok.

info.yml:

kind: readOnly
datacenters:
  main:
    entrypoint: !ENV '${ENTRYPOINT}'
    access_token: !ENV '${TOKEN}'
deployIn:
  labels:
    - all

Test:

$ overlord get-info -f info.yml -t projects --filter-per-project
...

If you see the projects on all the chains, that means everything is ok.

It's time to create the deployment files for our web server.

$ mkdir -p freenginx

freenginx/app.yml:

kind: directorProject
datacenters:
  main:
    entrypoint: !ENV '${ENTRYPOINT}'
    access_token: !ENV '${TOKEN}'
deployIn:
  labels:
    - desktop
projectName: freenginx
projectFile: |
  options:
    - alias:
    - ip4_inherit:
  services:
    www-server:
      makejail: !ENV '${OVERLORD_METADATA}/freenginx.makejail'

freenginx/metadata.yml:

kind: metadata
datacenters:
  main:
    entrypoint: !ENV '${ENTRYPOINT}'
    access_token: !ENV '${TOKEN}'
deployIn:
  labels:
    - desktop
metadataPrefix: freenginx
metadata:
  makejail: |
    OPTION start
    OPTION overwrite=force

    INCLUDE gh+DtxdF/efficient-makejail

    CMD mkdir -p /usr/local/etc/pkg/repos
    COPY ${OVERLORD_METADATA}/freenginx.pkg.conf /usr/local/etc/pkg/repos/FreeBSD.conf

    PKG freenginx

    CMD mkdir /tls
    COPY ${OVERLORD_METADATA}/freenginx.cert /tls/cert
    COPY ${OVERLORD_METADATA}/freenginx.key /tls/key

    COPY ${OVERLORD_METADATA}/freenginx.nginx.conf /usr/local/etc/freenginx/nginx.conf

    SYSRC nginx_enable=YES
    SERVICE nginx start
  nginx.conf: |
    worker_processes  auto;

    events {
      worker_connections  1024;
    }

    http {
      include       mime.types;
      default_type  application/octet-stream;

      sendfile        on;

      keepalive_timeout  65;

      server {
        listen 9532 ssl;
        http2 on;
        ssl_certificate /tls/cert;
        ssl_certificate_key /tls/key;

        location / {
            root   /usr/local/www/freenginx;
            index  index.html index.htm;
          }
        }

        ssl_protocols TLSv1.3;
        ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;
        ssl_prefer_server_ciphers off;
    }
  pkg.conf: |
    FreeBSD-ports: {
      url: "pkg+https://pkg.FreeBSD.org/${ABI}/latest",
      mirror_type: "srv",
      signature_type: "fingerprints",
      fingerprints: "/usr/share/keys/pkg",
      enabled: yes
    }

    FreeBSD-ports-kmods: {
      enabled: no
    }
include:
  - !ENV '${OVERLORD_WRKDIR}/secrets.yml'

freenginx/secrets.enc.yml:

Open this file with sops edit freenginx/secrets.enc.yml and add the following lines:

cert: |
    -----BEGIN CERTIFICATE-----
    MIIDnTCCAoWgAwIBAgIUO+/5mh/L+i/rb5c5euZoqskyzwwwDQYJKoZIhvcNAQEL
    BQAwXjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5
    MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xGTAXBgNVBAMMEHd3dzAwMS5ob21lLmFy
    cGEwHhcNMjYwNjE4MjA1ODQ5WhcNMjcwNjE4MjA1ODQ5WjBeMQswCQYDVQQGEwJV
    UzEOMAwGA1UECAwFU3RhdGUxDTALBgNVBAcMBENpdHkxFTATBgNVBAoMDE9yZ2Fu
    aXphdGlvbjEZMBcGA1UEAwwQd3d3MDAxLmhvbWUuYXJwYTCCASIwDQYJKoZIhvcN
    AQEBBQADggEPADCCAQoCggEBAJpjOv7A2lIO+3WzLO+eN2K5OHsmdOJs0voEv1bK
    j/zXq9nKsOEqQDJ/2kM5NubTZgFyPQrWaddvB+m6Ugd1OPEHQqum/WfPbdXcgFcO
    mdumIx7hMPVHGdQKrAOIXObQGJrpv0cpST1x3KbnAvc5yLQ5merVH0LFek33sCn+
    tNyMgihCJnXRNwY+hef2LV5GMnJw0JSOR2y8ydDDOzLhFeCpzomyguR1871plHvu
    uR+qAgTRUvy8Qi+Uxs2V4Rt2V4jzLu6riHnSCLWXfMm5nJW+aw5kTPcF/xHZW2sM
    dIG4bhtv6jx+eAVGCBDQIB57ulyQZsiwr2KJ663dWyLURukCAwEAAaNTMFEwHQYD
    VR0OBBYEFLunsOdAD01el9EsEuyOOSJ75Sj0MB8GA1UdIwQYMBaAFLunsOdAD01e
    l9EsEuyOOSJ75Sj0MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
    AApUDJYl2cozn3uCMZ3MsvQxx5XBaij1JPSBUDvK/cBu1iJxrUtoa1GV0fYX8lI1
    wSY/zSTQoqufoHIsw//bgDJuU20yHAptNGJrvRoS5zpYuwgiCgfg5W1dBjCFEgFx
    6T8lKaHwMdBJMrQSX0OlyG8dEq5g9g566O1IdanzNNi+iC+VY+JRLGkA1e+DcXGT
    3ofhWoBuBxojzlOZTfebN6hq0kA/xXrIcTLUOGLcurka3QJOV06M27lgMeapEgl0
    vlRS3Nd8aIrvbFyr8l4hRI42i70BFcAOFCWUvv3qyrLoQvVhIQpJTRLM62Uo6I5T
    jufbqxd/aXCLAbN4+OOS0fU=
    -----END CERTIFICATE-----
key: |
    -----BEGIN PRIVATE KEY-----
    MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaYzr+wNpSDvt1
    syzvnjdiuTh7JnTibNL6BL9Wyo/816vZyrDhKkAyf9pDOTbm02YBcj0K1mnXbwfp
    ulIHdTjxB0Krpv1nz23V3IBXDpnbpiMe4TD1RxnUCqwDiFzm0Bia6b9HKUk9cdym
    5wL3Oci0OZnq1R9CxXpN97Ap/rTcjIIoQiZ10TcGPoXn9i1eRjJycNCUjkdsvMnQ
    wzsy4RXgqc6JsoLkdfO9aZR77rkfqgIE0VL8vEIvlMbNleEbdleI8y7uq4h50gi1
    l3zJuZyVvmsOZEz3Bf8R2VtrDHSBuG4bb+o8fngFRggQ0CAee7pckGbIsK9iieut
    3Vsi1EbpAgMBAAECggEAIQIHtjlNxB8TaKv09sslLMyMdJn5ggKBzfYPYZM/2y9S
    POd+zzk9Df7zT42PPSUj6Tm/Ls6+RNLmhnRxPspzcObcPH5grd31rfRtlQ9YWlOI
    LT04viwkK8dXVQ8Fy8xgglho7qI3WDV8l0uLQQe/7zZkf8Zun1RAzKQg7C2ahg+I
    RSBXlh7r6K6hMu084AwFISvU7yZlUg1qohDsjstl+g8TWQf96NBz5WFRV08wZlCu
    uynU+Y82/p83bvCIPyMWFggQVf8rwQ1sLLYi+LCqR1xcPt18uW16EjPzoFfVye1g
    fQIFoW28tCwv5SX/bDWgmHshRctI8D3jJtcGmycwrQKBgQDTg4qfni1ogq+0xSFa
    RmiG890ZediqgZoVXEGHgs9RD2QjJwp1mOueccX4LiEAEbZH/ZkiPPnwe/Q/Vgv8
    k5EwdrnbGG6ixUBCmk5/Bx1dcCEA7oQ8L5FiXZPiRZO2jEB2hq3ct76PwamiQizY
    JdWh3FGGb2ed4ICT4gKZFgBodQKBgQC6290uwvLSK6+PRAef2nKGTAmLJ7+aUzaI
    tP2sXdJPkplmVvPgBk1+WPV4tf1p8+t6DFMthZGqBOPN5E/d/KjcYTVoBkebuE1w
    QGn6yjQpL3p2HD6MlwReOa+TtxsFjkGXaGy8msEQpdpOPcv4+I+lHMXhdcgWxh6j
    l2WjADq2JQKBgFrn80FtE2kSmf/gpdgN4Mj3sLRNWSDXOOkrUIK0ZvQY4Fn3Yphu
    U/4yOfrToJ1N/4DrbtB3UpjYPX6nNdmldsZUkMaotoxAqMC3XztbTHSnR5gF61GO
    xDZ5r6CVdMoFd4M5mSn+0ukoPAcf1/RCNpItheB4qxkAr2JfxewTt7MtAoGBAKOr
    iWU4JPCqiy/16qe986pmV8Wnn1BRqua7gabE1z4TroHRj/OeEaqlyP1eiwWPPaa9
    vO2WnSxK9C6X2M0cTdwa2Wiwd3CSUmIMScf97QpWJ/Hkc3U5of3WkU/VhrmrDRDN
    ytC4zHsEit8VieAd99QsC7ecLxKjnpq0NbY8sTBxAoGBAL++rwRObHxTOXrHuZ5R
    9Jonb+hSNG2IBKe5vBGnIwUMbnclFtT1EYaQNjJwjpS9lZt/+a+QhwUL+Tmd+3F2
    PETT+tB1W2dRLE6cpsUt/DgaPRXh7SMPkQXHRkJki2OUYwBlxI4da/JqU85pK+tF
    HSo4S8RPK1Rp/BK64Yyw2NKb
    -----END PRIVATE KEY-----

Console:

Now that we've written our deployment files, it's time to deploy them.

$ echo "secrets.yml" >> .gitignore
$ sops decrypt freenginx/secrets.enc.yml > freenginx/secrets.yml
$ overlord apply -f freenginx/metadata.yml
$ overlord apply -f freenginx/app.yml
$ overlord get-info -f freenginx/app.yml -t projects --filter-per-project
datacenter: http://100.65.139.52:8888
  entrypoint: main
  chain: None
  labels:
    - all
    - desktop
    - services
    - vm-only
    - dc-air
  projects:
    freenginx:
      state: UNFINISHED
      last_log: 2026-06-18_18h54m36s
      locked: True
      services:
        - {'name': 'www-server', 'status': 1, 'jail': '76ab7cf073'}
      up:
        operation: RUNNING
        last_update: 9.16 seconds
        job_id: 7
$ overlord get-info -f freenginx/app.yml -t projects --filter-per-project
datacenter: http://100.65.139.52:8888
  entrypoint: main
  chain: None
  labels:
    - all
    - desktop
    - services
    - vm-only
    - dc-air
  projects:
    freenginx:
      state: DONE
      last_log: 2026-06-18_18h54m36s
      locked: False
      services:
        - {'name': 'www-server', 'status': 0, 'jail': '76ab7cf073'}
      up:
        operation: COMPLETED
        output:
         rc: 0
         stdout: {'errlevel': 0, 'message': None, 'failed': []}
        last_update: 2 minutes and 46.29 seconds
        job_id: 7
        restarted: False
$ git add .
$ git commit -m 'Profit!'

That's it! We can create more deployment files just like we did with freenginx, store the secrets in both our dotenv and our secrets.yml, and use SOPS to edit them all, and then commit and push our changes to the repository (even if it's public).

Clone this wiki locally