La automatización del despliegue de contenedores tiene muchas ventajas, pero estas ventajas no están exentas de complicaciones. Los esfuerzos de DevOps han convertido en práctica común la codificación de credenciales en scripts de inicio en la nube, pero esto plantea importantes riesgos de seguridad. Además, ¿qué ocurre si necesitas introducir un certificado en una de estas instancias? ¿Lo guarda en una imagen o en un archivo de configuración? Esto supone un riesgo aún mayor, ya que ahora un adversario tiene acceso a una clave privada exportable. Usando herramientas como Puppet o Ansible junto con nuestra plataforma, podemos mitigar estos riesgos. Keyfactor Command podemos mitigar estos riesgos y solicitar el certificado de forma única para el contenedor o máquina virtual en el momento de su creación. Este post demostrará este concepto en el contexto de Microsoft Azure VMs.
La administración de contenedores requiere que dispongas de un sistema host (Azure recomienda CentOS 7.4, Ubuntu 16.04 LTS o SLES 12 SP2) con Ansible/Puppet, el SDK de Python y la CLI 2.0 de Azure. En este ejemplo, he puesto en marcha un B1 estándar con Ubuntu 16.04 LTS y corrió:
# install required packages
sudo apt-get update && sudo apt-get install -y libssl-dev libffi-dev python-dev python-pip
sudo pip install ansible[azure]
# add Azure CLI repo to package manager
AZ_REPO=$(lsb_release -cs)
echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | \
sudo tee /etc/apt/sources.list.d/azure-cli.list
curl -L https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add –
# install Azure CLI
sudo apt-get install apt-transport-https
sudo apt-get update && sudo apt-get install azure-cli
# the VM we will spin up will be running the yum package manager so we will need it on the host
# as well to acquire the proper Python bindings
sudo apt-get install yum
Después de configurar la máquina host, el siguiente paso es configurar la CLI de Azure para que te permita crear nuevas máquinas virtuales mediante programación. Para ello, ejecute:
az login
A continuación, introduzca el código dado en https://microsoft.com/devicelogin después de autenticarse en su portal Azure como el usuario con el que desea ejecutar Ansible. Deberías obtener un resultado similar:
[
{
"cloudName": "AzureCloud",
"id": " f9c3e574-235a-4998-a604-8a13b91e2100",
"isDefault": true,
"name": "Your Subscription Name"
"state": "Enabled",
"tenantId": " 4c00ebbc-e7cc-4790-bbbb-71dc5fb948e2",
"user": {
"name": "[email protected]",
"type": "user"
}
}
]
Ahora Ansible nos pedirá una clave SSH/par secreto para conectarnos a la nueva VM. Podemos generar esto con
ssh-keygen -t rsa -C [email protected]
Proporcionar un correo electrónico nos ayudará a identificar la clave en el futuro. Si guarda esto en la ubicación predeterminada, /home/(usuario actual)/.ssh/id_rsa, su clave pública debería residir en /home/iamgroot/.ssh/id_rsa.pub. Si ha protegido su clave privada con una frase de contraseña, deberá utilizar el agente SSH. El agente ayuda con la gestión de claves ssh cuando estás haciendo cosas en torno a la automatización. Para añadir la clave privada al agente, simplemente ejecute:
ssh-agent bash
ssh-agent add <Path to your Private Key>
Ahora podemos crear el Playbook de Ansible. Esto nos permitirá poner en marcha una máquina virtual de Azure, extraer un script de Python y solicitar un certificado con un solo command. Crea un nuevo archivo con extensión .yml, y configura lo siguiente:
- name: Provision Azure VM with Certificate
hosts: localhost
connection: local
tasks:
# The first thing the play will do is spin up
# a new Azure Virtual Machine on the same
# network.
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: AnsibleTest-Jake
allocation_method: Static
name: childVM1-ip
- name: Create Network Security Group that allows SSH
azure_rm_securitygroup:
resource_group: AnsibleTest-Jake
name: childVM1-nsg
rules:
- name: SSH
protocol: Tcp
destination_port_range: 22
access: Allow
priority: 1001
direction: Inbound
- name: Create virtual network inteface card
azure_rm_networkinterface:
resource_group: AnsibleTest-Jake
name: childVM1-nic
virtual_network: AnsibleTest-Jake-vnet
public_ip_name: childVM1-ip
subnet_name: default
security_group: childVM1-nsg
- name: Create VM
azure_rm_virtualmachine:
resource_group: AnsibleTest-Jake
name: childVM1
vm_size: Standard_DS1_v2
admin_username: azureuser
ssh_password_enabled: false
ssh_public_keys: # the ssh key used here is found in /home/<Your User>/.ssh/id_rsa.pub
- path: /home/azureuser/.ssh/authorized_keys
key_data: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDr4kQvWCZcqDbNOFHumbHUi1x6LAdeRImjmz79+srshS14cHsLD1qX5ATOhxWTZtfXZUG9UnlB2ag5I15b3xEVpo/eX9CnTMKWKpkiaQIfQgb20EdFgWE8dP9VXvdfTpJBGLOYKcmUbn/BnkKp3B1BWkp0YRiV8S1r1yYZxyFMGPcOJqwHwFyvJjxR8bGNIFWZ6tdZa+MCkoxSKk9IeIsCEHZhCTrMPceUZnzbKIU0waiwvnidZkRXjj//rQcDrcWyrem6pHS03f/Dt+1LpU50ahtp8we/SnlQNT+nYPiNcSzTSicPe0O1imSCB63bHLmtW/SRFTr8Yhsvq28VVAkV [email protected]"
network_interfaces: childVM1-nic
image:
offer: CentOS
publisher: OpenLogic
sku: '7.5'
version: latest
# in order to connect to the new host with Ansible,
# we must tell Ansible that it exists
- name: Get childVM1 IP to add to Ansible Inventory
azure_rm_publicipaddress_facts:
resource_group: AnsibleTest-Jake
name: childVM1-ip
register: azure_ip
- debug: var=azure_ip
- name: Add childVM1 to Ansible Inventory
add_host:
hostname: "{ { item.properties.ipAddress } }"
groupname: launched
ansible_ssh_private_key_file: ~/.ssh/id_rsa
ansible_ssh_user: azureuser
with_items: "{ { azure_ip.ansible_facts.azure_publicipaddresses } }"
- name: Add Epel Repository to Remote Host
yum_repository:
name: epel
description: EPEL YUM repo
baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
- name: Update Yum on Remote Host
yum:
name: '*'
state: latest
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
- name: Install Git on Remote Host
yum:
name: git
state: latest
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
- name: Create Git Download Directory
file: path=/home/azureuser/gitdl state=directory
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
# download python file from git repo
- name: Download API Result
git:
repo: https://gitlab.com/css-jadkins/Python-CMS-API-Call.git
dest: /home/azureuser/gitdl
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
- name: Set Execute Permissions
file:
path: /home/azureuser/gitdl/Enroll-PKCS12.py
owner: azureuser
mode: 0650
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
- name: Execute Python Script
command: python /home/azureuser/gitdl/Enroll-PKCS12.py
become: true
become_user: root
become_method: sudo
delegate_to: "{ { azure_ip.ansible_facts.azure_publicipaddresses[0].properties.ipAddress } }"
Now run the ansible playbook:
ansible-playbook azure_create_vm_basic.yml
Una vez completado, podrás iniciar sesión en childVM1 utilizando la uri ssh dada (desde la visión general de la VM en el portal de Azure). El cuadro de diálogo se verá algo como esto:
[azureuser@childVM1 ~]$ ssh [email protected]
The authenticity of host '137.116.85.88 (137.116.85.88)' can't be established.
ECDSA key fingerprint is SHA256:jJt9S1CVT/Mz8a4aC+l4G3fzbP1VBItlumbyvTEhGdg.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '137.116.85.88' (ECDSA) to the list of known hosts.
Enter passphrase for key '/home/iamgroot/.ssh/id_rsa': *************
[azureuser@childVM1 ~]$
Verás que tu archivo .pfx reside ahora en tu directorio personal. Ten en cuenta que puede que necesites añadir módulos pip a Ansible para resolver las dependencias de Python dependiendo de tu versión de Linux.
El script de Python utilizado en este ejemplo se encuentra en: https://gitlab.com/css-jadkins/Python-CMS-API-Call.