Post-Tyranny-Tech-Infrastru.../ansible/roles/authentik/tasks/flows.yml
Pieter 6cd6d7cc79 fix: Deploy all flow blueprints automatically (enrollment + recovery + 2FA)
CRITICAL FIX: Ensures all three flow blueprints are deployed during initial setup

The issue was that only custom-flows.yaml was being deployed, but
enrollment-flow.yaml and recovery-flow.yaml were created separately
and manually deployed later. This caused problems when servers were
rebuilt - the enrollment and recovery flows would disappear.

Changes:
- Updated flows.yml to deploy all three blueprints in a loop
- enrollment-flow.yaml: Invitation-only user registration
- recovery-flow.yaml: Password reset via email
- custom-flows.yaml: 2FA enforcement and brand settings

Now all flows will be available immediately after deployment:
✓ https://auth.dev.vrije.cloud/if/flow/default-enrollment-flow/https://auth.dev.vrije.cloud/if/flow/default-recovery-flow/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-15 13:48:40 +01:00

139 lines
4.8 KiB
YAML

---
# Configure Authentik flows (invitation, recovery, 2FA) via Blueprints
- name: Use bootstrap token for API access
set_fact:
authentik_api_token: "{{ client_secrets.authentik_bootstrap_token }}"
- name: Wait for Authentik API to be ready
shell: |
i=1
while [ $i -le 30 ]; do
if docker exec authentik-server curl -sf -H "Authorization: Bearer {{ authentik_api_token }}" http://localhost:9000/api/v3/flows/instances/ > /dev/null 2>&1; then
echo "Authentik API is ready"
exit 0
fi
echo "Waiting for Authentik API... attempt $i/30"
sleep 5
i=$((i+1))
done
exit 1
register: api_wait
changed_when: false
- name: Create blueprints directory on server
file:
path: "{{ authentik_config_dir }}/blueprints"
state: directory
mode: '0755'
- name: Copy flow blueprints to server
copy:
src: "{{ item }}"
dest: "{{ authentik_config_dir }}/blueprints/{{ item }}"
mode: '0644'
loop:
- custom-flows.yaml
- enrollment-flow.yaml
- recovery-flow.yaml
register: blueprints_copied
- name: Copy blueprints into authentik-worker container
shell: |
docker cp "{{ authentik_config_dir }}/blueprints/{{ item }}" authentik-worker:/blueprints/{{ item }}
loop:
- custom-flows.yaml
- enrollment-flow.yaml
- recovery-flow.yaml
when: blueprints_copied.changed
- name: Copy blueprints into authentik-server container
shell: |
docker cp "{{ authentik_config_dir }}/blueprints/{{ item }}" authentik-server:/blueprints/{{ item }}
loop:
- custom-flows.yaml
- enrollment-flow.yaml
- recovery-flow.yaml
when: blueprints_copied.changed
- name: Wait for blueprint to be discovered and applied
shell: |
echo "Waiting for blueprint to be discovered and applied..."
sleep 10
# Check if blueprint instance was created
i=1
while [ $i -le 24 ]; do
result=$(docker exec authentik-server curl -sf -H 'Authorization: Bearer {{ authentik_api_token }}' \
'http://localhost:9000/api/v3/managed/blueprints/' 2>/dev/null || echo '')
if echo "$result" | grep -q 'custom-flow-configuration'; then
echo "Blueprint instance found"
# Check if it has been applied successfully
if echo "$result" | grep -A 10 'custom-flow-configuration' | grep -q 'successful'; then
echo "Blueprint applied successfully"
exit 0
else
echo "Blueprint found but not yet applied, waiting..."
fi
else
echo "Waiting for blueprint discovery... attempt $i/24"
fi
sleep 5
i=$((i+1))
done
echo "Blueprint may still be applying, continuing..."
exit 0
register: blueprint_wait
changed_when: false
- name: Verify invitation stage was created
shell: |
docker exec authentik-server curl -sf -H "Authorization: Bearer {{ authentik_api_token }}" \
"http://localhost:9000/api/v3/stages/all/" | \
python3 -c "import sys, json; data = json.load(sys.stdin); stages = [s for s in data['results'] if 'invitation' in s.get('name', '').lower()]; print(json.dumps({'found': len(stages) > 0, 'count': len(stages)}))"
register: invitation_check
changed_when: false
failed_when: false
- name: Verify brand recovery flow was set
shell: |
docker exec authentik-server curl -sf -H "Authorization: Bearer {{ authentik_api_token }}" \
"http://localhost:9000/api/v3/core/brands/" | \
python3 -c "import sys, json; data = json.load(sys.stdin); brand = data['results'][0] if data['results'] else {}; print(json.dumps({'recovery_flow_set': brand.get('flow_recovery') is not None}))"
register: recovery_check
changed_when: false
failed_when: false
- name: Display flows configuration status
debug:
msg: |
========================================
Authentik Flows Configuration
========================================
Configuration Method: YAML Blueprints
Blueprints Deployed:
- /blueprints/custom-flows.yaml (2FA enforcement)
- /blueprints/enrollment-flow.yaml (invitation-only registration)
- /blueprints/recovery-flow.yaml (password reset via email)
✓ Blueprints Deployed: {{ blueprints_copied.changed }}
✓ Blueprints Applied: {{ 'Yes' if 'successfully' in blueprint_wait.stdout else 'In Progress' }}
Verification:
{{ invitation_check.stdout | default('Invitation stage: Checking...') }}
{{ recovery_check.stdout | default('Recovery flow: Checking...') }}
Note: Authentik applies blueprints asynchronously.
Changes should be visible within 1-2 minutes.
Flow URLs:
- Enrollment: https://{{ authentik_domain }}/if/flow/default-enrollment-flow/
- Recovery: https://{{ authentik_domain }}/if/flow/default-recovery-flow/
Email configuration is active - emails sent via Mailgun SMTP.
========================================