Ghost Hands - Automating The Stronghold With Ansible And Podman

Mission Update

Now we automate.

The pod.
The proxy.
The secrets.

One playbook to conjure the setup, one command to repeat the ritual.

Requirements

  • Ansible (core + community.containers)
  • Podman configured for rootless ops
  • X509 certs or automation for Let's Encrypt
  • Directory structure with:
    • roles/semaphore/tasks/main.yml
    • files/nginx.conf
    • files/cert.pem, key.pem (or auto-gen task)

Playbook Strategy

  • Create Podman pod
  • Deploy MySQL container
  • Deploy Semaphore UI container
  • Deploy NginX container with volumes mounted

Secret Externalization

Store credentials in group_vars/containers.yml and encrypt with Ansible Vault.

Step 1: Create The Pod

-  name:  Create the pod
   containers.podman.podman_pod:
     name: p_semaphore
     state: created
     ports:
      -  "4430:443"

Step 2: Activate the MySQL Container

-  name:  Create the MySQL container
   containers.podman.podman_container:
     name: semaphore_mysql
     pod: p_semaphore
     state: started
     rm:  true
     detach:  true
     image: docker.io/mysql:lts
     volumes:
      - semaphore_mysql:/var/lib/mysql
     env:
       MYSQL_RANDOM_ROOT_PASSWORD:  'yes'
       MYSQL_DATABASE: semaphore
       MYSQL_USER: semaphore
       MYSQL_PASSWORD:  " {{  semaphore_mysql_pw  }} "

Step 3: Initiate the Semaphore container

-  name:  Create the Semaphore container
   containers.podman.podman_container:
     name: semaphore
     pod: p_semaphore
     state: started
     rm:  true
     detach:  true
     image: docker.io/semaphoreui/semaphore:latest
     env:
       SEMAPHORE_DB_USER: semaphore
       SEMAPHORE_DB_PASS:  " {{  semaphore_mysql_pw  }} "
       SEMAPHORE_DB_HOST: 127.0.0.1
       SEMAPHORE_DB_PORT: 3306
       SEMAPHORE_DB_DIALECT: mysql
       SEMAPHORE_DB: semaphore
       SEMAPHORE_PLAYBOOK_PATH: /tmp/semaphore/
       SEMAPHORE_ADMIN_PASSWORD:  " {{  semaphore_admin_pw  }} "
       SEMAPHORE_ADMIN_NAME: admin
       SEMAPHORE_ADMIN_EMAIL: admin@localhost
       SEMAPHORE_ADMIN: admin
       SEMAPHORE_ACCESS_KEY_ENCRYPTION: gs72mPntFATGJs9qK0pQ0rKtfidlexiMjYCH9gWKhTU=
       SEMAPHORE_LDAP_ACTIVATED:  'no'
       TZ: UTC

Step 4: The NginX Reverse Proxy

-  name:  Create the NginX container
   containers.podman.podman_container:
     name: semaphore_proxy
     pod: p_semaphore
     state: started
     rm:  true
     detach:  true
     image: docker.io/library/nginx
     volumes:
      -  " {{  role_path  }} /files/nginx.conf:/etc/nginx/conf.d/default.conf:ro"
      -  " {{  role_path  }} /files/cert.pem:/etc/nginx/cert.pem:ro"
      -  " {{  role_path  }} /files/key.pem:/etc/nginx/key.pem:ro"

Step 5: Verify

Log in.
Verify the configuration.
Monitor the logs with podman pod logs p_semaphore.

Final Signal

The stronghold stands.
Provisioned in silence. Hardened by code.

But this is just the surface. A faint signal.
There is much to do for a strong signal.

Need the full Ansible role?

  • Variables ready
  • Templates in place
  • Handlers sharpened
  • Deploy once, repeat forever

Buy the hardened role + full guide - forged in the silence.

Whisper to DeadSwitch on Matrix: @deadswitch:matrix.org
Maybe the Ghost signals back.

DeadSwitch | The Silent Architect
In silence, I rise. In structure, I endure.