Gardience Documentation gardience.com →
Docs / Installation

Attach to an existing Salt master

In attach mode, Gardience does not run its own Salt master. It connects to the salt-api of a master you already run (Salt 3006.x, 3007.x or 3008.x), and your agents stay connected to that master. The Gardience server runs only the web front end, the Gardience service and the playbook runner.

Attach mode takes two parts: install Gardience pointed at your salt-api, then make a few one-time changes on your Salt master.

Before you start

Part 1: install Gardience in attach mode

To install:

  1. Extract the bundle as described in Install on one server.
  2. Run the installer with --attach:

    sudo ./install/install.sh \
      --attach https://salt-master.example.com:8000 \
      --eauth pam \
      --attach-master-ip 10.0.0.10 \
      --master-address salt-master.example.com \
      --admins alice \
      --approvers bob,carol \
      --hostname gardience.example.com \
      --license /path/to/gardience-license.json
  3. When it finishes, the installer prints the console address and points you to ATTACH.md in the install folder (/opt/gardience/ATTACH.md by default). That file holds the master-side steps with your values filled in. Follow it in Part 2.

Attach options

OptionDefaultWhat it does
--attach URLnot setTurns on attach mode. The URL of your salt-api. Gardience sends all its Salt requests there, and the console's base pages are served from it.
--eauth TYPEfileThe eauth type Gardience's service accounts (gardience-scanner and gardience-automation) sign in with on your master.
--insecure-salt-apioffAccept a self-signed salt-api certificate. Without it, Gardience checks the certificate.
--attach-master-ip IPnoneThe only address allowed to reach /gardience/internal/ on the Gardience server. Your master's single sign-on and vault modules call this endpoint. Without this option the endpoint answers no one, so those modules cannot reach Gardience.
--admins A,BnoneUser names from your master's eauth who administer Gardience. Admins also approve. If you give none, nobody has admin rights in Gardience until you set them with gardience roles.
--approvers A,BnoneUser names who may approve runs that someone else launched (the two-person rule).

Also useful in attach mode:

What the installer does differently

In attach mode the installer:

Part 2, the quick way: one command

From the Gardience server, with SSH access to your master as a user who can sudo:

sudo /opt/gardience/gardience attach-setup admin@salt-master.example.com --admins alice --approvers bob,carol

It copies the attach kit to the master (a root-only temporary folder, deleted afterwards) and runs setup-master.sh there. You can also copy attach-kit/ to the master yourself and run sudo ./setup-master.sh in it.

The setup reads your master's configuration with Salt's own loader, so your included files and master.d drop-ins count exactly as Salt counts them. It then shows a plan and changes nothing until you confirm (--yes skips the question, --dry-run only shows the plan):

It stops instead of guessing on a syndic setup or an eauth type other than file, PAM or LDAP: use the manual steps below there. After you change file_roots, external_auth, ext_pillar or reactor in your own files, or after gardience automation commands on|off, run gardience attach-kit and the setup again (a rerun is safe).

The steps below are what the command does, for doing it by hand.

Part 2: set up your Salt master

Do these once on the Salt master, then restart salt-master and salt-api. The values in capitals are in the .env file in the Gardience install folder. That file is readable by root only:

sudo grep -E '^(SVC_PASS|AUTOMATION_PASS|GARDIENCE_INTERNAL_TOKEN|GARDIENCE_SSO_KEY)=' /opt/gardience/.env
  1. Console files. Copy attach-kit/saltgui to /srv/saltgui on the master.
  2. Gardience content. Copy attach-kit/srv to /srv/gardience and add it as a second file root:

    file_roots:
      base: [/srv/salt, /srv/gardience]
  3. salt-api. Enable rest_cherrypy, serve the console, and enable the clients Gardience uses:

    rest_cherrypy:
      port: 8000
      ssl_crt: /path/to/cert.pem
      ssl_key: /path/to/key.pem
      app: /srv/saltgui/saltgui/index.html
      static: /srv/saltgui/saltgui/static
      static_path: /static
    netapi_enable_clients: [local, local_async, runner, wheel]
    worker_threads: 8     # salt-api and Gardience share the request server
    token_expire: 3600    # 1-hour sessions, so role changes apply quickly
  4. Master-side modules for single sign-on and the secrets vault. Load them and add the vault as an external pillar:

    salt-run saltutil.sync_auth && salt-run saltutil.sync_pillar
    ext_pillar:
      - gardience_vault: {}

    Give the salt-master and salt-api processes these environment variables, for example with a systemd drop-in using Environment=:

    VariableValue
    GARDIENCE_INTERNAL_URLhttps://<Gardience host>:<console port>/gardience
    GARDIENCE_INTERNAL_TOKENGARDIENCE_INTERNAL_TOKEN from .env
    GARDIENCE_SSO_KEYGARDIENCE_SSO_KEY from .env
    GARDIENCE_INTERNAL_CAPath to the Gardience certificate, if the master does not already trust it

    The Gardience server answers /gardience/internal/ only from the address you gave with --attach-master-ip.

  5. Accounts. In the eauth type you chose, create the two service accounts with the passwords from .env: gardience-scanner (password SVC_PASS) and gardience-automation (password AUTOMATION_PASS). Then grant them, and your people, rights in external_auth. ATTACH.md lists the exact grants. In short:

    • gardience-scanner gets read-only functions, @jobs and @wheel key.list_all and key.finger_master (this server's ID, which the license is bound to).
    • gardience-automation gets the functions Gardience calls (listed in ATTACH.md, never .*), @jobs, the gardience_match.members and gardience_match.end_sessions runners and @wheel key.list_all, key.accept and key.reject (node approval, decided by admins in the console).
    • People, admins included, get gdn:.* plus read-only functions (admins also @wheel key.list_all, key.finger and config.values, and every role the cache.grains runner). A gdn: grant is never matched by Salt itself, so it works only through Gardience, which applies approvals, change tickets, windows and locks first. Give no person .*, @runner or @wheel beyond these: raw Salt access stays with root on the master, your break-glass.
    • config.values returns the master's whole configuration. Keep secrets (such as auth.ldap.bindpw) out of the master's configuration files, or leave config.values out.
    • The gardience_sso entries map single sign-on roles (gardience-admin%, gardience-operator%, gardience-approver%, gardience-viewer%) to their rights.
  6. Enrollment from an Ansible inventory (optional). Set autosign_grains_dir: /etc/salt/autosign_grains and share the Gardience file config/autosign/gardience_enroll into that folder. Skip this if you approve agent keys by hand.
  7. Drift auto-repair. Add the reactor:

    reactor:
      - 'salt/beacon/*/service/*':
        - /srv/gardience/reactor/drift.sls
  8. Sync to agents:

    salt '*' saltutil.sync_all
  9. Recommended hardening. Salt lets an agent send batched events under any tag except a short blocklist, and that list does not include job returns, so a compromised agent could fake another agent's result. If you run no syndic, add "salt/job/*/ret/*" to MINION_EVENT_BLACKLIST in salt/daemons/masterapi.py. Gardience's own master image does this. Repeat it after every Salt upgrade.
  10. Who administers and approves. If you did not pass --admins and --approvers, or to change them later, run this on the Gardience server:

    sudo /opt/gardience/gardience roles --admins alice --approvers bob,carol

    The service reads the change right away, with no restart. Run gardience roles with no options to show the current lists. Names may use letters, digits, _, ., @ and -. People who sign in with single sign-on get their role from their identity provider group instead.

Check that it works

Within a few minutes, Overview > Dashboard lists your nodes. If it stays empty, the banner at the top of the console says what failed. Most often it is step 5: the scanner account needs @wheel key.list_all and @jobs.

Limits in attach mode

Gardience by Bouziden Management LLC.