Hostvar not working as expected

I know that I am just missing something, but I think that I have been staring at this too long to figure out what I am missing. I have the following in my host vars file:

certs: [
   myfishbowl.com: {
    csr_path: "/etc/pki/myfishbowl.com/csr.pem",
    common_name: "myfishbowl.com",
    san: ["*.myfishbowl.com"],
    cert_path: "/etc/pki/myfishbowl.com/cert.pem",
    fullchain_dest: "/etc/pki/myfishbowl.com/fullchain.pem",
    chain_dest: "/etc/pki/myfishbowl.com/chain.pem"
  }
]

and then I am trying to reference it in a task like:

- name: Generate CSR
  community.crypto.openssl_csr:
    path: "{{ item['csr_path'] }}"
    private_key_path: "{{ hostvars[inventory_hostname].private_key_path }}"
    common_name: "{{ item.common_name }}"
    owner: root
    group: root
    mode: 0640
    subject_alt_name: "{{ item.san |default(omit) }}"
  loop: "{{ hostvars[inventory_hostname]['certs'] }}" 

and I am getting an error that things such as csr_path are undefined.

What you missing is the myfishbowl.com level.

- name: Generate CSR
  community.crypto.openssl_csr:
    path: "{{ item['myfishbowl.com']['csr_path'] }}"  # or "{{ item['myfishbowl.com'].csr_path }}" 
    private_key_path: "{{ hostvars[inventory_hostname].private_key_path }}"
    common_name: "{{ item['myfishbowl.com'].common_name }}"
    owner: root
    group: root
    mode: 0640
    subject_alt_name: "{{ item['myfishbowl.com'].san |default(omit) }}"
  loop: "{{ hostvars[inventory_hostname]['certs'] }}" 
1 Like

Ok, so how can I loop that, since each machine could have more than one cert? I thought that using certs as the subscript for the hostvars would make the myfishbowl.com the “item”.

You’ve got a weird mix of yaml and json going on there. I started to mention that at first but didn’t want to confuse the issue. Your certs is exactly the same as

    certs:
      - myfishbowl.com:
          csr_path: "/etc/pki/myfishbowl.com/csr.pem"
          common_name: "myfishbowl.com"
          san:
            - "*.myfishbowl.com"
          cert_path: "/etc/pki/myfishbowl.com/cert.pem"
          fullchain_dest: "/etc/pki/myfishbowl.com/fullchain.pem"
          chain_dest: "/etc/pki/myfishbowl.com/chain.pem"

which I find easier to read, but you do you.
So "{{ certs[0].keys() }}" will give the single-element list: ['myfishbowl.com']. Maybe that’s what you want, but since you’ve got the same value in common_name maybe not? Maybe you want this:

    certs:
      - csr_path: "/etc/pki/myfishbowl.com/csr.pem"
        common_name: "myfishbowl.com"
        san:
          - "*.myfishbowl.com"
        cert_path: "/etc/pki/myfishbowl.com/cert.pem"
        fullchain_dest: "/etc/pki/myfishbowl.com/fullchain.pem"
        chain_dest: "/etc/pki/myfishbowl.com/chain.pem"
      - csr_path: "/etc/pki/yourfishbowl.com/csr.pem"
        common_name: "yourfishbowl.com"
        san:
          - "*.yourfishbowl.com"
        cert_path: "/etc/pki/yourfishbowl.com/cert.pem"
        fullchain_dest: "/etc/pki/yourfishbowl.com/fullchain.pem"
        chain_dest: "/etc/pki/yourfishbowl.com/chain.pem"
      - [… another cert …]
      - [… and yet another cert …]
1 Like

That is what I want. Thank you! I knew that I stared at this too long and overthought the whole thing.

1 Like

hostvars[inventory_hostname] is an anti-pattern; variables from the inventory host should be accessed directly, since that’s the default source of variables.

  loop: "{{ certs }}"
1 Like