A playbook sets secrets_dir: /etc/httpd/secrets and secrets_dest: "{{ secrets_dir }}/htpasswd" in its vars block. Is a variable built from another variable valid, and why is it quoted?
Yes. Variables are evaluated lazily, when a task uses them, so secrets_dest becomes /etc/httpd/secrets/htpasswd. It must be quoted because the value starts with {{.
vars:
web_pkg: apache2
web_svc: apache2
httpdconf_src: files/000-default.conf
httpdconf_dest: /etc/apache2/sites-enabled/000-default.conf
htaccess_src: files/.htaccess
secrets_dir: /etc/httpd/secrets
secrets_src: files/htpasswd
secrets_dest: "{{ secrets_dir }}/htpasswd"
web_root: /var/www/html
Ansible does not resolve {{ }} when it reads the vars block. It stores the template string, and resolves it when a task uses secrets_dest. So the order of definitions doesn't matter, and if secrets_dir is later overridden (by -e, for instance), secrets_dest follows automatically.
That is the payoff of defining the directory once: the task that creates the directory and the task that copies the password file into it can never disagree about the path.
Go deeper:
Templating (Jinja2) (official docs) โ how and when templates are evaluated.