Задача — во время выполнения роли скопировать на удалённый хост PEM-ключ.
Для этого используем ansible-vault.
Идея состоит в том, что мы зашифруем содержимое ключа в переменную, а затем используем модуль copy — и создадим на удалённой системе новый файл.
Содержание
Создание сертификата
Сначала создадим сам сертификат и приватный ключ с помощью openssl:
[simterm]
$ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
[/simterm]
Проверяем содержимое:
[simterm]
$ openssl x509 -text -noout -in certificate.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
44:f4:a2:d1:c5:03:a8:f4:78:34:6a:b3:26:45:ef:23:07:dd:a2:34
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
Validity
Not Before: Feb 5 09:10:00 2019 GMT
Not After : Feb 5 09:10:00 2020 GMT
Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
...
[/simterm]
Шифрование данных
Сначала создадим файл, в котором будет храниться пароль для расшифровки данных:
[simterm]
$ cat ~/.ssh/mobilebackend_aws_credentials.yml oigh7fengeiG
[/simterm]
Далее этот файл будет сохранён в Jenkins как Secret file, и будет использоваться для расшифровки данных Ansible:
Создаём второй файл — сюда добавим имя переменной и сам ключ.
Создаём каталог для файлов в роли deploy:
[simterm]
$ mkdir roles/deploy/files
[/simterm]
Создаём в нём новый файл — apns-{{ env }}.pem.yml.
В переменную {{ env }} подставим значение, переданное из group_vars/hostname.yml, т.е. dev, stage или production:
[simterm]
$ cat group_vars/mobilebackend-dev.yml | grep -w env env: "dev"
[/simterm]
Вызываем ansible-vault с опцией create, указываем путь к файлу с паролем:
[simterm]
$ ansible-vault create roles/deploy/files/apns-dev.pem.yml --vault-password-file ~/.ssh/mobilebackend_aws_credentials.yml
[/simterm]
Откроется окно редактирования, вносим имя переменной и значение:
Сохраняем и закрываем файл — и Ansible зашифрует его:
[simterm]
$ head -5 roles/deploy/files/apns-dev.pem.yml $ANSIBLE_VAULT;1.1;AES256 63313035646361303936636338313837353133623461363661363232316361623662316366343833 3335363539653530396336663936653262663534663339360a316364326335306562306666373737 31646538303038613063613837383231633039626561626666353338653662633661613230656463 3731653433383932330a353538323664633337653638393563343132626430663131373738653035
[/simterm]
Если надо отредактировать файл после создания — используем edit:
[simterm]
$ ansible-vault edit roles/deploy/files/apns-dev.pem.yml --vault-password-file ~/.ssh/mobilebackend_aws_credentials.yml
[/simterm]
Другой вариант — сначала создать plaintext-файл roles/deploy/files/apns-dev.pem.yml, а потом зашифровать его с помощью encrypt:
[simterm]
$ ansible-vault encrypt roles/deploy/files/apns-dev.pem.yml --vault-password-file ~/.ssh/mobilebackend_aws_credentials.yml
[/simterm]
Ansible copy
Последним шагом остаётся добавить задачу копирования файла.
Разбиваем её на две части — в одной используем include_vars, в получаем значение переменной из roles/deploy/files/apns-dev.pem.yml, во второй — создадим на удалённой системе новый файл с текстом из переменной apns_certificate_key.
Проверяем возможность прочитать переменную вообще.
Тут Ansible вызывается скриптом из поста AWS: миграция RTFM 3.0 (final) – CloudFormation и Ansible роли, в котором есть функция ansible_exec():
...
ansible_exec () {
local tags=$1
local env=$2
local vault=$3
local rsa=$4
local connection=$5
local application=$6
ansible-playbook --private-key $rsa --tags "$1" --limit=$env mobilebackend.yml --vault-password-file $vault --extra-vars "$connection $application"
}
...
Запускаем, проверяем:
[simterm]
$ ./ansible_exec.sh -t deploy
Tags: deploy
Env: mobilebackend-dev
Vault: /home/setevoy/.ssh/mobilebackend_aws_credentials.yml
RSA: /home/setevoy/Work/example/aws-credentials/bm-backend-dev.pem
APP:
Are you sure to proceed? [y/n] y
...
TASK [deploy : Check certificate content] ****
ok: [dev.backend-app2-internal.example.world] => {
"msg": "Certificate body: -----BEGIN PRIVATE KEY-----\nMII***LJH\n-----END PRIVATE KEY-----\n"
...
[/simterm]
Хорошо — переменная считалась, тело сертификата получили — добавляем задачу с copy:
...
- name: "Deploy APNS certificate"
copy:
dest: "/data/projects/{{ backend_project_name }}/common/config/apns-certificate.pem"
content: "{{ apns_certificate_key }}"
owner: "{{ backend_project_name }}"
group: "{{ backend_project_name }}"
mode: 0400
when: "'yoga' in backend_project_name and 'console' in inventory_hostname"
...
Тут в dest указываем путь на удалённой системе, а в content — подставляем значение из переменной apns_certificate_key.
Задаём пользователя, группу и права — {{ backend_project_name }} и права 400.
В условии when проверяем какой проект деплоится, т.к. создавать ключи нам надо только для проекта «yoga» и на хосте в имени которого есть слово console (dev.backend-console-internal.example.world) в переменной inventory_hostname.
Имя проекта передаётся через переменную APP_PROJECT_NAME джобы в Jenkins, и считывается в плейбуке проекта:
...
- role: deploy
tags: deploy
backend_prodject_git_branch: "{{ lookup('env','APP_REPO_BRANCH') }}"
backend_project_git_repo: "{{ lookup('env','APP_REPO_RUL') }}"
backend_project_name: "{{ lookup('env','APP_PROJECT_NAME') }}"
when: "'backend-bastion' not in inventory_hostname"
Сейчас задаём переменную вручную:
[simterm]
$ export APP_PROJECT_NAME=yoga
[/simterm]
Запускаем:
[simterm]
...
TASK [deploy : Read APNS certificate from the apns-dev.pem.yml] ****
ok: [dev.backend-app1-internal.example.world]
skipping: [dev.backend-bastion.examplee.world]
ok: [dev.backend-app2-internal.example.world]
ok: [dev.backend-console-internal.example.world]
TASK [deploy : Check certificate content] ****
ok: [dev.backend-app1-internal.example.world] => {
"msg": "Certificate body: -----BEGIN PRIVATE KEY-----\nMII***LJH\n-----END PRIVATE KEY-----\n"
}
...
TASK [deploy : Deploy APNS certificate] ****
...
skipping: [dev.backend-bastion.example.world]
changed: [dev.backend-console-internal.example.world]
...
[/simterm]
Проверяем на удалённом хосте наличие файла, пользователя и права доступа:
[simterm]
root@bttrm-dev-console:/home/admin/Scripts# ll /data/projects/yoga/common/config/apns-certificate.pem -r-------- 1 yoga yoga 1704 Feb 5 12:06 /data/projects/yoga/common/config/apns-certificate.pem
[/simterm]
И содержимое:
[simterm]
root@bttrm-dev-console:/home/admin/Scripts# head -5 /data/projects/yoga/common/config/apns-certificate.pem -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCziHZIiFYYriVb hRWDN2cR5j6wHpK3+CEc2rXl+Umc6m8el/jcJX3uVIckfmFfsapvpSO3MD0gkhKI knJw48rhUlk3FUsTF7/pmstYIAxu7APc5nphiTt6YyNlp8L1xc0tKCuxSvcLDmR8 OiMbGE5Rm9EXXi4E6UAibFe9VQfZSsle9pzZCC+lDD4Rh1TLjOju/w4fnXprXkDY
[/simterm]
Готово.

