call a role with different parameters from the same playbook

117 views
Skip to first unread message

Eric Belhomme

unread,
Mar 22, 2017, 1:40:49 PM3/22/17
to Ansible Project
Hello the list,

I'm quite new in Ansible world and I just wrote an Ansible role and playbook to handle my Let's Encrypt SSL certificates.

Here is my role :

---

# create/update SSL/TLS certificate using letsencrypt service
#

- name: check & install openssl package
  apt:
    update_cache: yes
    cache_valid_time: 3600
    name: openssl

- name: copy the accountkey
  copy:
    src: 'letsencrypt_account.key'
    dest: '/tmp/letsencrypt_account.key'
    owner: root
    group: root
    mode: 0400
  delegate_to: 127.0.0.1

- name: check if the private key exists
  stat:
    path: "{{ ssl_cert_key }}"
  register: sslcert_key_exists

- name: create RSA private key if not exist
  command: "openssl genrsa -out {{ ssl_cert_key }} 2048"
  when: sslcert_key_exists.stat.exists != True

- name: check if the CRT exists
  stat:
    path: "{{ ssl_cert_crt }}"
  register: sslcert_crt_exists

- name: create an initial csr
  shell: 'openssl req -key {{ ssl_cert_key }} -new -out {{ ssl_cert_csr }}
    -subj "/C=FR/ST=Bouches du Rhone/L=Fuveau/O=Ricozome/OU=mailgate/CN={{ ansible_hostname }}.ricozome.net"
    -reqexts SAN
    -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName={{ ssl_cert_subjectAltName }}"))'
  args:
    executable: /bin/bash
  when:  sslcert_crt_exists.stat.exists != True

- name: create the CSR from the existing certificate
  command: "openssl x509 -in {{ ssl_cert_crt }} -signkey {{ ssl_cert_key }} -x509toreq -out {{ ssl_cert_csr }}"
  when: sslcert_crt_exists.stat.exists == True

- name: check SSL certificate
  letsencrypt:
    acme_directory: "{{ ssl_acme_directory }}"
    challenge: 'dns-01'
    account_key: '/tmp/letsencrypt_account.key'
    account_email: "{{ ssl_cert_email }}"
    csr: "{{ ssl_cert_csr }}"
    dest: "{{ ssl_cert_crt }}"
    remaining_days: 10
  register: sslcert_challenge

- name: create nsupdate request
  template:
    src: nsupdate.j2
    dest: "/tmp/nsupdate_{{ ansible_hostname }}.tmp"
  delegate_to: 127.0.0.1
  when: sslcert_challenge|changed

- name: add letsencrypt challenge DNS record
  command: "nsupdate -k {{ ssl_nsupdate_key}} /tmp/nsupdate_{{ ansible_hostname }}.tmp"
  delegate_to: 127.0.0.1
  when: sslcert_challenge|changed
  register: sslcert_challenge_replied
 
- name: reply to letsencrypt challenge
  letsencrypt:
    acme_directory: "{{ ssl_acme_directory }}"
    challenge: 'dns-01'
    account_key: '/tmp/letsencrypt_account.key'
    csr: "{{ ssl_cert_csr }}"
    dest: "{{ ssl_cert_crt }}"
    data: "{{ sslcert_challenge }}"
  when: sslcert_challenge_replied
  register: sslcert_updated


And here is my playbook

 ---

- name: Let's Encrypt certificate maintenance
  hosts: seamus

  vars:
    ssl_cert_key: '/etc/ssl/private/letsencrypt_seamus_https.key'
    ssl_cert_csr: '/tmp/letsencrypt_seamus_https.csr'
    ssl_cert_crt: '/etc/ssl/certs/letsencrypt_seamus_https.pem'
    ssl_cert_fullchain_crt: '/etc/ssl/certs/letsencrypt_seamus_https_fullchain.pem'
    ssl_cert_email: 'host...@example.com'
    ssl_cert_subjectAltName: 'DNS:example.com,DNS:seamus.example.com,DNS:webmail.example.com'
    ssl_nsupdate_key: '/home/rico/scripts/dns/Kexample.com.+157+40531.key'

  roles:
    - role: sslcert

  tasks:
    - name: restart nginx
      systemd:
        name: nginx
        state: reloaded
      when: sslcert_updated


As you can see, I declare variables used by my sslcert role in the playbook, then I call the role, and everything run smoothly.
But now I would like to use my role to generale more than once per server : for a given server, I have to generate *many* certificates because it run TLS/SMTP, and IMAP over SSL, and SASL LDAP, and I want one cert per service !

How can I archieve this with a single playbook ? 

Thanks for your suggestions,

Eric

Phonthip Namkaew

unread,
Mar 22, 2017, 3:37:10 PM3/22/17
to Ansible Project
a)
Call playbook several times using parameter --extra-vars to provide a different set of
Vars each time

b)
Call the role several times in the playbook with a different set of vars each time

Read the docs regarding extra-vars and role vars

Eric Belhomme

unread,
Mar 23, 2017, 11:42:09 AM3/23/17
to Ansible Project
Hello,

Thanks to you suggestion, I re-factored my code and putting the variables into vars/meddle.yml :

- ssl_certs:
  - mailgate:
      key: '/etc/ssl/private/letsencrypt_meddle.example.com_mailgate.key'
      csr: '/tmp/letsencrypt_meddle.example.com_mailgate.csr'
      crt: '/etc/ssl/certs/letsencrypt_meddle.example.com_mailgate.pem'
      fullchain_crt: '/etc/ssl/certs/letsencrypt_meddle.example.com_mailgate_fullchain.pem'
      email: 'postm...@example.com'
      subjectAltName: 'DNS:mail.example.com,DNS:smtp.example.com,DNS:imap.example.com'
  - http:
      key: '/etc/ssl/private/letsencrypt_meddle.example.com_http.key'
      csr: '/tmp/letsencrypt_meddle.example.com_http.csr'
      crt: '/etc/ssl/certs/letsencrypt_meddle.example.com_http.pem'
      fullchain_crt: '/etc/ssl/certs/letsencrypt_meddle.example.com_http_fullchain.pem'
      email: 'webm...@example.com'
      subjectAltName: 'DNS:example.com,DNS:www.example.com,DNS:webmail.example.com,DNS:photo.example.com'


The playbook looks now like this :

---

- name: test certificate creation
  hosts: meddle
  strategy: debug

  vars_files:
    - "vars/defaults.yml"
    - "vars/meddle.yml"

  roles:
    - { role: sslcert, ssl_cert: ssl_certs.mailgate }
    - { role: sslcert, ssl_cert: ssl_certs.http }

But unfortunately this doesn't work : my variable "ssl_cert" does not contain what I expect :

TASK [sslcert : check if the private key exists] *******************************
fatal: [meddle]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'ansible.parsing.yaml.objects.AnsibleUnicode object' has no attribute 'key'\n\nThe error appears to have been in '/etc/ansible/roles/sslcert/tasks/main.yml': line 25, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: check if the private key exists\n  ^ here\n"}
Debugger invoked
(debug) p vars['ssl_cert']
u'ssl_certs.mailgate'
(debug) p vars['ssl_certs']
[{u'mailgate': {u'crt': u'/etc/ssl/certs/letsencrypt_meddle.example.com_mailgate.pem',
                u'csr': u'/tmp/letsencrypt_meddle.example.com_mailgate.csr',
                u'email': u'postm...@example.com',
                u'fullchain_crt': u'/etc/ssl/certs/letsencrypt_meddle.example.com_mailgate_fullchain.pem',
                u'key': u'/etc/ssl/private/letsencrypt_meddle.example.com_mailgate.key',
                u'subjectAltName': u'DNS:mail.example.com,DNS:smtp.example.com,DNS:imap.example.com'}},
 {u'http': {u'crt': u'/etc/ssl/certs/letsencrypt_meddle.example.com_http.pem',
            u'csr': u'/tmp/letsencrypt_meddle.example.com_http.csr',
            u'email': u'webm...@example.com',
            u'fullchain_crt': u'/etc/ssl/certs/letsencrypt_meddle.example.com_http_fullchain.pem',
            u'key': u'/etc/ssl/private/letsencrypt_meddle.example.com_http.key',
            u'subjectAltName': u'DNS:example.com,DNS:www.example.com,DNS:webmail.example.com,DNS:photo.example.com'}}]


Where am I wrong ???

Thanks,

Eric

Kai Stian Olstad

unread,
Mar 23, 2017, 12:19:00 PM3/23/17
to ansible...@googlegroups.com
What do you expect it to contain?
Since you haven't provided the role code I'll have to guess you are
using ssl_cert.key, ssl_cert.csr and so on in you role code.
If so you need change the vars file to:

ssl_certs:
mailgate:
key: '/etc/ssl/private/letsencrypt_meddle.example.com_mailgate.key'
csr: '/tmp/letsencrypt_meddle.example.com_mailgate.csr'
crt: '/etc/ssl/certs/letsencrypt_meddle.example.com_mailgate.pem'
fullchain_crt:
'/etc/ssl/certs/letsencrypt_meddle.example.com_mailgate_fullchain.pem'
email: 'postm...@example.com'
subjectAltName:
'DNS:mail.example.com,DNS:smtp.example.com,DNS:imap.example.com'
http:
key: '/etc/ssl/private/letsencrypt_meddle.example.com_http.key'
csr: '/tmp/letsencrypt_meddle.example.com_http.csr'
crt: '/etc/ssl/certs/letsencrypt_meddle.example.com_http.pem'
fullchain_crt:
'/etc/ssl/certs/letsencrypt_meddle.example.com_http_fullchain.pem'
email: 'webm...@example.com'
subjectAltName:
'DNS:example.com,DNS:www.example.com,DNS:webmail.example.com,DNS:photo.example.com'

And roles to:
- { role: sslcert, ssl_cert: '{{ ssl_certs.mailgate }}' }
- { role: sslcert, ssl_cert: '{{ ssl_certs.http }}' }

--
Kai Stian Olstad

Michael Bubb

unread,
Mar 29, 2017, 9:05:15 AM3/29/17
to Ansible Project, ansible-pr...@olstad.com
I am a little confused in this discussion - looks like the OP is using individual certs but  Kai Stian Olstad, you are using a SAN cert, no?

I am currently working on getting a playbook together to manage a SAN cert on haproxy - works pretty well but still a few manual steps.

Kai Stian Olstad

unread,
Mar 29, 2017, 10:30:23 AM3/29/17
to ansible...@googlegroups.com
On 29. mars 2017 15:05, Michael Bubb wrote:
> I am a little confused in this discussion - looks like the OP is using
> individual certs but Kai Stian Olstad, you are using a SAN cert, no?

I just took the OP variable ssl_certs and changed it from a list to a
dict, to make it work when providing parameters to the role.

--
Kai Stian Olstad
Reply all
Reply to author
Forward
0 new messages