Help Dynamically Generating CSP Nginx Include

I am trying to insert Ansible variables into an nginx-include file. Unfortunately, I do not know enough about Ansible’s tasks YML format to accomplish this.

The goal is to insert the domain name from the {{ wordpress_sites }} dictionary into a CSP file so I can test Content Security Policies from development to production without hard-coding the domain name.

Directory

My nginx-includes direction looks like this:

├── nginx-includes
    └── example.com
        └── csp.conf.j2

csp.conf.j2

add_header Content-Security-Policy "default-src 'none'; script-src https://{{ item }};

What I’ve Tried

I have tried the following only to receive errors on vagrant reload --provision

  1. Adding with_dict: "{{ wordpress_sites }}" to every name in roles/wordpress-setup/tasks/nginx-includes.yml
  2. Adding {{ wordpress_sites }} inside the with_items: line

The farthest I get is if I just add {{ item }} in csp.conf.js to output the following which is just the nginx path:

add_header Content-Security-Policy "default-src 'none'; script-src https://nginx-includes/example.com/csp.conf.j2

self

I know I can use self in CSP, but if I can add variables from this dictionary then I could add other variables that would be needed.

Any help would be greatly appreciated. Thank you.

Thanks for posting what you’ve tried.

You discovered that {{ item }} returns nginx-includes/example.com/csp.conf.j2. This is because the template task creating that file is using with_items (a standard loop), where each item is a template file name.

If you switch your strategy from include-files to child-templates, the template task creating your child template will use with_dict (thus looping over hashes), where each item.value.somevar is the value of somevar in a site from wordpress_sites. See example usages of item.value in the wordpress-site.conf.j2 template.

Follow the docs for creating a child template, maybe something like this (untested):

{% extends 'roles/nginx/templates/nginx.conf.j2' %}

  {% block server_basic -%}
  {{ super() }}
  add_header Content-Security-Policy "default-src 'none'; script-src https://{{ site_hosts_canonical | join(' https://') }};
  {% endblock %}

(see jinja2 join filter)

You’ll see how site_hosts_canonical is just a helper variable that itself uses item.value.site_hosts and the jinja2 map filter.


P.S., If your Trellis is up-to-date, you can apply the nginx changes more quickly than
vagrant reload --provision because reloading (rebooting) the VM is not necessary, nor is most of the provision process. Try this:

ANSIBLE_TAGS=nginx-includes vagrant provision
1 Like

Thank you very much for the response.

I apologize for the delay as it took me awhile to figure how to use the child-template.

Since there is a lot of customization for each site host I ended up creating a lot of these files if there were multiple hosts per Trellis installation. Therefore, I ended up creating a simple feature request on GitHub.

Also, this tip was golden!

ANSIBLE_TAGS=nginx-includes vagrant provision

Is there anyway to skip the checking/downloading of vender/roles during that command?

▶ ANSIBLE_TAGS=nginx-includes vagrant provision
==> default: Running provisioner: ansible...
    default: Running ansible-galaxy...
- downloading role 'composer', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-composer/archive/1.5.0.tar.gz
...

Thanks again for your help.

That’s an annoying feature of Vagrant right now which is being fixed I think.

Anyway, you can use SKIP_GALAXY=true ANSIBLE_TAGS=nginx-includes vagrant provision

3 Likes