A standard for roles #7

Open
opened 2020-05-15 15:21:26 +00:00 by caskd · 1 comment
Owner

The usual setup of a service should follow the following formula:

  • Install dependencies (if any)
  • Does the package have to be built?
    • Yes - Pull the stable/latest and build
    • No - Install package
  • Does the package create the necessary directories?
    • No - Create the directories or mount the volumes
  • Copy configuration files (if any)
    • Mode: 600 or less (no read access other than the service)
    • Handler: Reload the service
  • Create unpriviledged users (if needed)
  • Create service file that meets the standards mentioned below
    • Handlers:
      • Reload systemd daemon
      • Restart service
  • Set up firewall
    • include firewall role
    • set firewall rule array with required rules
    • save firewall rules (reboot persistance)

The templates should follow a very straightforward approach

  • Is the option going to be changed if the setup/host changes?
    • No - can be written in the file (not necessarily configurable)
    • Yes:
      • Use a programmable approach for every repetition
      • Optional configuration options should be able to be toggled by a boolean var
      • Vault vars should use a separate namespace for every service

Discovery/linking of services

  • All information related to position of the service should be stored under group_vars/all (globally accessible)
  • Does the service linked support DNS?
    • No - Use IPs of ansible hosts from that group, never hardcode IPs
    • Yes - Use DNS records for discovery. Use the highest ones that work for that service
      • SRV - Automatic HOST:PORT mapping via DNS
      • CNAME - Automatic service -> hostname mapping
      • A - Automatic service -> host IP mapping

Filesystem tree and content examples
Moved from/Merged with #6

group_vars
|- all
|- service1
|- serviceN
roles
|- service1
|  |- tasks
|  |  |- main.yml
|  |- handlers
|  |  |- main.yml
|  |- vars
|  |  |- main.yml
|  |- vault
|  |  |- keys.yml (if any)
|  |  |- database.yml (if any db connections)
group.yml
  • The group.yml should contain the roles needed for that group
- hosts: group1
  roles:
        - service1
        - service2
        - serviceN
        - firewall
  • The group_vars/all should contain the necessary information described before
  • The group.yml should contain variables that describe configuration and deployment simplified and in-depth as well (with comments)
service1:
        port: 1337
        config:
                modules:
                        - { module: "example1", loaded: true}
                        - { module: "example2", loaded: false}
                mode: "active"
service2:
        accounts:
                - { user: "root", password: "hunter12"}
                - { user: "git", pubkey: "ssh-rsa XXXXXXX..."}
        enabled: true
firewall:
        - { port: 1337, proto: "tcp", net: "any"}
        - { port: 42069, proto: "any", net: "eth0"}

SystemD service standards

  • Service files should be:
    • Stored at /etc/systemd/system
    • Only overrides if service file is already provided service1.service.d/override.conf
      • Global template should be used here
  • Priviledge boundaries of the services:
    • Root filesystem access:
      • inacessible
      • tmpfs
      • read-only root
    • Read-only lib/config paths
      • /etc paths must be separated to prevent cross-service config reading
    • Read-write data paths (ideally volumes)
    • unpriviledged UUIDs (root is outside host UUID range)
    • unpriviledged write operations (no setuid/setgid, no unsafe paths/links)
    • filtered syscalls (if the needed calls are known)
    • set capabilities
  • Restart policy
    • always restart
      • 10-30 second delay

Security - File permissions

  • Read permissions should be split as such:
    • Users only: standalone service or non shared configuration
    • Groups and users: shared configuration and file access (sockets aswell)
    • Global access: non-critical data (seedbox files)
  • Write permissions
    • Permanent storage (usually only on volumes, avoid keeping data on a host)
    • Temporary files (tmpfs)
  • Execute permissions
    • Scripts/programs called by a service (that themselves are unwritable to avoid RCE)

Variables contexts

The variables should be split in different "contexts" to signal where a variable comes from and to prevent overwriting of them.

Global variables which come from group_vars/all should be part of the global key
Global variables which come from group_vars/all should be part of the hosts.HOSTX key
Group variables which are defined in groupX.yml don't need a key. They are used for configuring the roles they use.

Here's a tree that shows a example of the contexts:

global:
    group1:
        role1:
            service1:
                var1: "xxxx"
host:
    host1:
        group2:
            role5:
                service4:
                    var1: "zxzx"
                    var2: "yxyx"
            role2:
                service3:
                    - { itemx: "zzzz", date: "xx-yy-zz", toggle: true }
...
**The usual setup of a service should follow the following formula:** - Install dependencies (if any) - Does the package have to be built? + Yes - Pull the stable/latest and build + No - Install package - Does the package create the necessary directories? + No - Create the directories or mount the volumes - Copy configuration files (if any) + Mode: 600 or less (no read access other than the service) + Handler: Reload the service - Create unpriviledged users (if needed) - Create service file that meets the standards mentioned below + Handlers: * Reload systemd daemon * Restart service - Set up firewall + include firewall role + set firewall rule array with required rules + save firewall rules (reboot persistance) **The templates should follow a very straightforward approach** - Is the option going to be changed if the setup/host changes? + No - can be written in the file (not necessarily configurable) + Yes: * Use a programmable approach for every repetition * Optional configuration options should be able to be toggled by a boolean var * Vault vars should use a separate namespace for every service **Discovery/linking of services** - All information related to position of the service should be stored under group_vars/all (globally accessible) - Does the service linked support DNS? + No - Use IPs of ansible hosts from that group, never hardcode IPs + Yes - Use DNS records for discovery. Use the highest ones that work for that service * SRV - Automatic HOST:PORT mapping via DNS * CNAME - Automatic service -> hostname mapping * A - Automatic service -> host IP mapping **Filesystem tree and content examples** Moved from/Merged with #6 ```txt group_vars |- all |- service1 |- serviceN roles |- service1 | |- tasks | | |- main.yml | |- handlers | | |- main.yml | |- vars | | |- main.yml | |- vault | | |- keys.yml (if any) | | |- database.yml (if any db connections) group.yml ``` - The `group.yml` should contain the roles needed for that group ```yaml - hosts: group1 roles: - service1 - service2 - serviceN - firewall ``` - The `group_vars/all` should contain the necessary information described before - The `group.yml` should contain variables that describe configuration and deployment simplified and in-depth as well (with comments) ```yaml service1: port: 1337 config: modules: - { module: "example1", loaded: true} - { module: "example2", loaded: false} mode: "active" service2: accounts: - { user: "root", password: "hunter12"} - { user: "git", pubkey: "ssh-rsa XXXXXXX..."} enabled: true firewall: - { port: 1337, proto: "tcp", net: "any"} - { port: 42069, proto: "any", net: "eth0"} ``` **SystemD service standards** + Service files should be: - Stored at `/etc/systemd/system` - Only overrides if service file is already provided `service1.service.d/override.conf` * Global template should be used here + Priviledge boundaries of the services: - Root filesystem access: * inacessible * tmpfs * read-only root - Read-only lib/config paths * `/etc` paths must be separated to prevent cross-service config reading - Read-write data paths (ideally volumes) - unpriviledged UUIDs (root is outside host UUID range) - unpriviledged write operations (no setuid/setgid, no unsafe paths/links) - filtered syscalls (if the needed calls are known) - set capabilities + Restart policy - always restart * 10-30 second delay **Security - File permissions** + Read permissions should be split as such: - Users only: standalone service or non shared configuration - Groups and users: shared configuration and file access (sockets aswell) - Global access: non-critical data (seedbox files) + Write permissions - Permanent storage (usually only on volumes, avoid keeping data on a host) - Temporary files (tmpfs) + Execute permissions - Scripts/programs called by a service (that themselves are unwritable to avoid RCE) **Variables contexts** The variables should be split in different "contexts" to signal where a variable comes from and to prevent overwriting of them. Global variables which come from `group_vars/all` should be part of the `global` key Global variables which come from `group_vars/all` should be part of the `hosts.HOSTX` key Group variables which are defined in `groupX.yml` don't need a key. They are used for configuring the roles they use. Here's a tree that shows a example of the contexts: ```yml global: group1: role1: service1: var1: "xxxx" host: host1: group2: role5: service4: var1: "zxzx" var2: "yxyx" role2: service3: - { itemx: "zzzz", date: "xx-yy-zz", toggle: true } ... ```
Author
Owner

Thanks to t.me/timhok for the firewall idea.

Тимур, [15.05.20 17:34]
nothing about firewall and networking
Тимур, [15.05.20 17:34]
maybe services also should come with firewall files
Тимур, [15.05.20 17:35]
if your host system uses firewalld or something that supports it

Thanks to t.me/timhok for the firewall idea. > Тимур, [15.05.20 17:34] > nothing about firewall and networking > Тимур, [15.05.20 17:34] > maybe services also should come with firewall files > Тимур, [15.05.20 17:35] > if your host system uses firewalld or something that supports it
This repo is archived. You cannot comment on issues.
No Label
No Milestone
No Assignees
1 Participants
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: RedXen/ansible#7
No description provided.