DEBOPS.AUTHORIZED_KEYS(5)

NAME
debops.authorized_keys - Manage SSH public keys using Ansible

SYNOPSIS

debops service/authorized_keys [--limit group,host,...] [--diff] [--check] [--tags tag1,tag2,...] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

The debops.authorized_keys role can be used to manage SSH keys centrally in the /etc/ssh/authorized_keys/ directory. The role only manages the keys themselves, you should configure the sshd service to use them separately, for example by using the debops.sshd Ansible role.

GETTING STARTED

  Security considerations

The debops.authorized_keys role is designed to manage files in /etc/ssh/authorized_keys/ directory which contain SSH public keys for user accounts.

By default, role modifies the ownership and permissions of these files after the Ansible authorized_key changes them, so that the owner of these files is root account, and the file group, either named after the specified username, set as an item.group parameter or root if the previous entries don't result in an existing group present on a given system. This assumes that each user account has a primary group of the same name as their account, and they are the only members of that group.

The file attributes will be set as 640 to allow read only access to the SSH public key files. This should ensure that user accounts can be logged into the specific SSH public keys, but they cannot be modified by their respective users.

Unfortunately, it seems that the Ansible authorized_key module enforces the "600" file permissions <https://github.com/ansible/ansible-modules-core/blob/devel/system/authorized_key.py#L298-L302> on any file change, therefore there exists a window of opportunity between the given user file being updated by the authorized_key module and permissions being enforced again by the file Ansible module. At the moment there's no good solution to this issue, perhaps in the future the authorized_key module will be updated to allow for setting custom file ownership and permissions similarly to the file module. However, if there are no updates to the user files, the permissions are not changed.

  SSH service configuration

The debops.authorized_keys role does not manage the sshd service configuration by itself. Instead, you are expected to configure the sshd daemon to use the authorized keys from its directory, either by hand or by an Ansible role.

NOTE: The debops.sshd role enables use of the SSH public keys managed by the debops.authorized_keys automatically.

To enable the sshd service to use the configured public keys, you should change the configuration in the /etc/ssh/sshd_config file to something like this:

# /etc/ssh/sshd_config
AuthorizedKeysFile /etc/ssh/authorized_keys/%u %h/.ssh/authorized_keys

The above configuration will enable use of the configured keys by all subsequent SSH connections.

You can use the Match keyword to restrict the use of the authorized keys to a particular hosts, users, groups or IP addresses/subnets as needed. For example, if you want to check these authorized keys only for users in a specific subnet, you can do it like this:

# /etc/ssh/sshd_config
Match Address 192.0.2.0/24
      AuthorizedKeysFile /etc/ssh/authorized_keys/%u %h/.ssh/authorized_keys

Alternatively, you can use different conditions to restrict the SSH public keys checked by the sshd daemon to only the authorized keys maintained by this role. For example, to restrict a particular system group to only use these authorized keys for authentication, you can do it like this:

# /etc/ssh/sshd_config
Match Group sftponly
      AuthorizedKeysFile /etc/ssh/authorized_keys/%u

  Example inventory

This role is included by default in the common.yml DebOps playbook, so you don't need to do anything to enable it.

  Example playbook

If you are using this role without DebOps, here's an example Ansible playbook that uses the debops.authorized_keys role:

---
- name: Manage SSH public keys
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_all_hosts', 'debops_service_authorized_keys' ]
  become: True
  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'
  roles:
    - role: authorized_keys
      tags: [ 'role::authorized_keys', 'skip::authorized_keys' ]

DEFAULT VARIABLE DETAILS

Some of debops.authorized_keys default variables have more extensive configuration than simple strings or lists, here you can find documentation and examples for them.

  authorized_keys__list

The authorized_keys__list, authorized_keys__group_list, authorized_keys__host_list and authorized_keys__dependent_list variables are used to define what SSH keys should be present in each user file located in /etc/ssh/authorized_keys/ directory. Each list entry is a YAML dictionary with specific parameters:

name
    Required. Name of the user account to configure. This will be used as the name of the file located in the /etc/ssh/authorized_keys/ directory.

    These parameters are related to SSH public key management:

sshkeys
    Optional. String containing either a SSH public key, or an URL to a resource which returns a file with SSH public keys (only one URL is allowed at the moment), or a YAML list of SSH public keys.

github
    Optional. String with the name of a GitHub account. SSH public keys belonging to this account will be added to, or removed from, the specified user file. The SSH keys will be downloaded from: https://github.com/<username>.keys Only one GitHub account is allowed at a time.

options
    Optional. String or list of SSH options which should be set for each key specified on the sshkeys list. You can find more about available options in authorized_keys(5) <https://manpages.debian.org/authorized_keys(5)>.

    If this parameter is not specified, SSH public keys will use options set in the authorized_keys__default_options variable. To override this variable for a particular entry, set the item.options parameter as empty string or list.

    The specified SSH key options are applied to all keys specified in the sshkeys or github parameters in this specific entry. To use different key options for different SSH keys, specify them in separate entries on the list.

key_options
    Optional. Additional set of options to add to the SSH public keys. This can be used with item.options parameter to easily combine a list of options from another variable with a custom additional options. For example:

    authorized_keys__list:
      - name: 'user'
        github: 'user'
        options: '{{ authorized_keys__options_map.strict }}'
        key_options: 'command="ls -l /home/user"'

exclusive
    Optional, boolean. If defined and True, role will remove all other SSH public keys located in the user file and set only the SSH public keys present in the item.sshkeys or item.github parameters.

state
    Optional. If undefined or present, the SSH public keys specified in the item.sshkeys or item.github parameters will be added to the user file. If absent, the specified SSH public keys will be removed from the user file.

    These parameters are related to the files located in the /etc/ssh/authorized_keys/ directory:

readonly
    Optional, boolean. If defined and True, or if the corresponding authorized_keys__readonly variable is True, the role will set the owner and group of the user file as root:<item.group|primary group of user|root> and its permissions will be set to 0640, so that the respective users being in their own groups can still access the file and use it for authentication, but they cannot change it.

    If this parameter is set to False or the corresponding authorized_keys__readonly variable is False, to role will not modify the file ownership or permissions set by the authorized_key Ansible module.

owner
    Optional. Set the owner of the user file. If the owner account does not exist, root will become the owner.

group
    Optional. Name of the primary group of a given user file. If the specified group does not exist, it will be automatically created by the role.

    If the item.group parameter is not specified, the role will try to set the group of the file the same as the specified user in item.name parameter with the assumption that the corresponding primary group exists. If it does not exist, the primary group of the user file will be root.

system
    Optional, boolean. If undefined or True, the group created by the role will be a "system" group, with GID < 1000. If False, the created group will be a "normal" group with GID >= 1000. The existing groups are not modified.

gid Optional. Specify the GID a given group should use.

mode
    Optional. Set the mode of the user file. If not specified, mode 0640 or 0600 will be set depending on read only configuration parameters.

file_state
    Optional. If undefined or present, the user file will be present. If absent, the user file will be removed.

  Examples

Ensure that given SSH public keys are present in the user file:

authorized_keys__list:
  - name: 'user1'
    sshkeys: [ 'ssh-rsa AAAAB3NzaC1yc2EAAAA...', 'ssh-rsa AAAAB3NzaC1yc2EAAAA...' ]

Add SSH public keys from specified URL:

authorized_keys__list:
  - name: 'user2'
    sshkeys: 'https://auth.example.com/api/ssh/user2'

Add SSH keys from two GitHub accounts to specified user account:

authorized_keys__list:
  - name: 'app1'
    github: 'user-one'
  - name: 'app1'
    github: 'user-two'

Set SSH keys from a file on Ansible Controller as the only keys on a given user account:

authorized_keys__list:
  - name: 'user3'
    sshkeys: '{{ lookup("file", "/path/to/user3.pub") }}'
    exclusive: True

AUTHOR
Maciej Delmanowski

COPYRIGHT
2014-2022, Maciej Delmanowski, Nick Janetakis, Robin Schneider and others