Compare commits

...

9 Commits

Author SHA1 Message Date
uumas
fea49be8d1 Use service-specific oauth2-proxy instances 2025-09-14 03:10:20 +03:00
uumas
aaca377811 service: Support static ip for service container 2025-09-14 03:09:28 +03:00
uumas
0b73582f36 container: Support static ip for container 2025-09-14 03:08:24 +03:00
uumas
ad50e05ee9 network: Support static subnet 2025-09-14 03:07:28 +03:00
uumas
12f32f5824 network: Support macvlan driver 2025-09-14 03:07:03 +03:00
uumas
586f98bc9f synapse: Use federation port 8448 2025-09-14 03:05:06 +03:00
uumas
a29908b507 podman: Ensure auto update timer is enabled 2025-09-14 03:04:22 +03:00
uumas
c96997a4ec lint 2025-09-13 17:36:05 +03:00
uumas
014edb08ac service: fix template mounts for additional containers 2025-08-28 11:02:35 +03:00
27 changed files with 206 additions and 76 deletions

View File

@@ -4,6 +4,7 @@ container_user: ""
container_mounts: [] container_mounts: []
container_publish_ports: [] container_publish_ports: []
container_networks: [] container_networks: []
container_ip: ""
container_secrets: [] container_secrets: []
container_env: {} container_env: {}
container_auto_start: true container_auto_start: true

View File

@@ -115,6 +115,11 @@ argument_specs:
required: false required: false
default: [] default: []
elements: str elements: str
container_ip:
description: IPv4 address for the container in the first network defined in container_networks
type: str
required: false
default: ""
container_secrets: container_secrets:
description: A list of secrets available to the container as file or environment variable description: A list of secrets available to the container as file or environment variable
type: list type: list

View File

@@ -15,10 +15,16 @@
name: network name: network
vars: vars:
network_name: "{{ network }}" network_name: "{{ network }}"
network_subnet: >-
{{
container_ip | ansible.utils.ipsubnet(24)
if (container_ip | length > 0 and network_index == 0) else ''
}}
when: network_created_networks is not defined or network not in network_created_networks when: network_created_networks is not defined or network not in network_created_networks
loop: "{{ container_networks }}" loop: "{{ container_networks }}"
loop_control: loop_control:
loop_var: network loop_var: network
index_var: network_index
- name: Create volumes for container {{ container_name }} - name: Create volumes for container {{ container_name }}
ansible.builtin.include_role: ansible.builtin.include_role:
@@ -45,7 +51,7 @@
command: "{{ container_command or omit }}" command: "{{ container_command or omit }}"
user: "{{ container_user or omit }}" user: "{{ container_user or omit }}"
mount: "{{ _container_mounts | map('items') | map('map', 'join', '=') | map('join', ',') }}" mount: "{{ _container_mounts | map('items') | map('map', 'join', '=') | map('join', ',') }}"
network: "{{ container_networks | map('regex_replace', '$', '.network') }}" network: "{{ _container_networks_with_ip }}"
publish: "{{ container_publish_ports }}" publish: "{{ container_publish_ports }}"
secrets: "{{ _container_secrets }}" secrets: "{{ _container_secrets }}"
env: "{{ container_env }}" env: "{{ container_env }}"

View File

@@ -1,6 +1,17 @@
--- ---
_container_image: "{{ container_image | replace('/', '_') ~ '.image' }}" _container_image: "{{ container_image | replace('/', '_') ~ '.image' }}"
_container_networks: "{{ container_networks | map('regex_replace', '$', '.network') }}"
_container_networks_with_ip: >-
{{
[
_container_networks[0] ~ (
':ip=' ~ container_ip if container_ip | length > 0 else ''
)
]
+ _container_networks[1:]
}}
_container_volumes: "{{ container_mounts | selectattr('type', '==', 'volume') }}" _container_volumes: "{{ container_mounts | selectattr('type', '==', 'volume') }}"
_container_mount_sources: "{{ container_mounts | map(attribute='source') }}" _container_mount_sources: "{{ container_mounts | map(attribute='source') }}"

View File

@@ -0,0 +1,3 @@
---
network_driver: bridge
network_subnet: ""

View File

@@ -0,0 +1,7 @@
---
- name: Restart network service {{ network_name }}
ansible.builtin.systemd_service:
name: "{{ network_name }}-network.service"
state: restarted
daemon_reload: true
ignore_errors: "{{ ansible_check_mode }}"

View File

@@ -7,3 +7,16 @@ argument_specs:
description: Name of the network. Must be unique within a host. description: Name of the network. Must be unique within a host.
type: str type: str
required: true required: true
network_driver:
description: Driver to manage the network
type: str
required: false
default: bridge
choices:
- bridge
- macvlan
network_subnet:
description: Subnet for the network
type: str
required: false
default: ""

View File

@@ -1,10 +1,17 @@
--- ---
- name: "Create container network service {{ network_name }}" - name: Create container network service {{ network_name }}
containers.podman.podman_network: containers.podman.podman_network:
name: "{{ network_name }}" name: "{{ network_name }}"
state: quadlet state: quadlet
quadlet_file_mode: "0644" quadlet_file_mode: "0644"
notify: Reload systemd daemon driver: "{{ network_driver }}"
subnet: "{{ network_subnet if network_subnet | length > 0 else omit }}"
quadlet_options: >-
{{
['Options=parent=' ~ ansible_default_ipv4.interface]
if network_driver == 'macvlan' else []
}}
notify: Restart network service {{ network_name }}
- name: Add network to created networks variable - name: Add network to created networks variable
ansible.builtin.set_fact: ansible.builtin.set_fact:

View File

@@ -1 +0,0 @@
Sets up a oauth2-proxy container

View File

@@ -1,17 +0,0 @@
---
argument_specs:
main:
description: "Sets up a oauth2-proxy container"
options:
oauth2_proxy_oidc_issuer_url:
description: the OpenID Connect issuer URL
type: str
required: true
oauth2_proxy_client_id:
description: the OAuth client ID
type: str
required: true
oauth2_proxy_client_secret:
description: the OAuth client secret
type: str
required: true

View File

@@ -1,24 +0,0 @@
---
- name: OAuth2 Proxy
ansible.builtin.import_role:
name: service
vars:
service_name: oauth2-proxy
service_container_image: "quay.io/oauth2-proxy/oauth2-proxy:latest-alpine"
service_container_http_port: 4180
service_container_command:
- --config
- /oauth2-proxy.cfg
- --client-secret-file
- /run/secrets/client_secret
service_container_mounts:
- type: template
source: oauth2-proxy.cfg.j2
destination: /oauth2-proxy.cfg
service_container_secrets:
- name: cookie_secret
length: 32
type: env
target: OAUTH2_PROXY_COOKIE_SECRET
- name: client_secret
value: "{{ oauth2_proxy_client_secret }}"

View File

@@ -1,11 +0,0 @@
# OAuth2 Proxy Configuration
http_address = "0.0.0.0:4180"
# OIDC Provider Configuration
provider = "oidc"
oidc_issuer_url = "{{ oauth2_proxy_oidc_issuer_url }}"
client_id = "{{ oauth2_proxy_client_id }}"
code_challenge_method = "S256"
skip_provider_button = "true"
email_domains = "*"

View File

@@ -4,3 +4,9 @@
name: name:
- podman - podman
- aardvark-dns - aardvark-dns
- name: Ensure podman auto update timer is enabled
ansible.builtin.systemd_service:
name: podman-auto-update.timer
state: started
enabled: true

View File

@@ -7,6 +7,7 @@ service_vhost_locations: []
service_proxy_pass_host_header: true service_proxy_pass_host_header: true
service_proxy_auth_type: none service_proxy_auth_type: none
service_container_ip: ""
service_container_additional_networks: [] service_container_additional_networks: []
service_container_user: "" service_container_user: ""
service_container_publish_ports: [] service_container_publish_ports: []

View File

@@ -1,7 +1,14 @@
--- ---
- name: "Restart socat socket for {{ service_name }}" - name: Restart socat socket for {{ service_name }}
ansible.builtin.systemd_service: ansible.builtin.systemd_service:
name: "{{ service_name }}-socat.socket" name: "{{ service_name }}-socat.socket"
state: restarted state: restarted
daemon_reload: true daemon_reload: true
ignore_errors: '{{ ansible_check_mode }}' ignore_errors: '{{ ansible_check_mode }}'
- name: Restart socat socket for {{ service_name ~ '-oauth2-proxy' }}
ansible.builtin.systemd_service:
name: "{{ service_name }}-oauth2-proxy-socat.socket"
state: restarted
daemon_reload: true
ignore_errors: '{{ ansible_check_mode }}'

View File

@@ -36,7 +36,6 @@ argument_specs:
service_proxy_auth_type: service_proxy_auth_type:
description: >- description: >-
Set to oauth2-proxy to use OAuth2 Proxy for vhost authentication. Set to oauth2-proxy to use OAuth2 Proxy for vhost authentication.
The oauth2-proxy role must be run separately.
type: str type: str
required: false required: false
default: none default: none
@@ -49,6 +48,20 @@ argument_specs:
required: false required: false
default: [] default: []
service_oauth2_proxy_issuer_url:
description: >-
OpenID Connect issuer URL. Required if service_proxy_auth_type is oauth2-proxy.
type: str
required: false
oauth2_proxy_client_id:
description: OAuth client ID. Required if service_proxy_auth_type is oauth2-proxy.
type: str
required: false
oauth2_proxy_client_secret:
description: OAuth client secret. Required if service_proxy_auth_type is oauth2-proxy.
type: str
required: false
service_container_image: service_container_image:
description: "The image to run in the service container(s), in FQIN format (registry/imagename:tag)." description: "The image to run in the service container(s), in FQIN format (registry/imagename:tag)."
type: str type: str
@@ -75,6 +88,11 @@ argument_specs:
type: str type: str
required: false required: false
default: "" default: ""
service_container_ip:
description: Static ip for the container in it's network
type: str
required: false
default: ""
service_container_additional_networks: service_container_additional_networks:
description: >- description: >-
A list of additional podman networks for the service container (in A list of additional podman networks for the service container (in

View File

@@ -34,6 +34,7 @@
container_mounts: "{{ _service_container_mounts }}" container_mounts: "{{ _service_container_mounts }}"
container_publish_ports: "{{ service_container_publish_ports }}" container_publish_ports: "{{ service_container_publish_ports }}"
container_networks: "{{ _service_container_networks }}" container_networks: "{{ _service_container_networks }}"
container_ip: "{{ service_container_ip }}"
container_secrets: "{{ _service_container_secrets }}" container_secrets: "{{ _service_container_secrets }}"
container_env: "{{ service_container_env }}" container_env: "{{ service_container_env }}"
container_requires: "{{ _service_container_requires }}" container_requires: "{{ _service_container_requires }}"
@@ -43,6 +44,9 @@
- name: Socat for {{ service_name }} - name: Socat for {{ service_name }}
ansible.builtin.include_tasks: socat.yaml ansible.builtin.include_tasks: socat.yaml
when: service_container_http_port > 0 when: service_container_http_port > 0
vars:
socat_service_name: "{{ service_name }}"
socat_target_http_port: "{{ service_container_http_port }}"
- name: Reverse proxy for {{ service_name }} - name: Reverse proxy for {{ service_name }}
ansible.builtin.include_tasks: proxy.yaml ansible.builtin.include_tasks: proxy.yaml

View File

@@ -0,0 +1,36 @@
---
- name: OAuth2 Proxy container for {{ service_name }}
ansible.builtin.import_role:
name: container
vars:
container_name: "{{ service_name }}-oauth2-proxy"
container_image: "quay.io/oauth2-proxy/oauth2-proxy:latest-alpine"
container_command:
- --client-secret-file
- /run/secrets/client-secret
- --cookie-secret-file
- /run/secrets/cookie-secret
container_networks:
- "{{ service_name }}-oauth2-proxy"
container_secrets:
- name: "{{ service_name }}-oauth2-proxy-cookie-secret"
length: 32
target: cookie-secret
- name: "{{ service_name }}-oauth2-proxy-client-secret"
value: "{{ service_oauth2_proxy_client_secret }}"
target: client-secret
container_env:
OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
OAUTH2_PROXY_PROVIDER: oidc
OAUTH2_PROXY_OIDC_ISSUER_URL: "{{ service_oauth2_proxy_issuer_url }}"
OAUTH2_PROXY_CLIENT_ID: "{{ service_oauth2_proxy_client_id }}"
OAUTH2_PROXY_CODE_CHALLENGE_METHOD: S256
OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: "true"
OAUTH2_PROXY_EMAIL_DOMAINS: "*"
container_auto_update: "{{ service_auto_update }}"
- name: Socat for OAuth2 Proxy for {{ service_name }}
ansible.builtin.import_tasks: socat.yaml
vars:
socat_service_name: "{{ service_name }}-oauth2-proxy"
socat_target_http_port: 4180

View File

@@ -1,4 +1,8 @@
--- ---
- name: OAuth2 proxy for {{ service_name }}
ansible.builtin.include_tasks: oauth2_proxy.yaml
when: _service_oauth2_proxy
- name: Reverse proxy for {{ service_name }} - name: Reverse proxy for {{ service_name }}
ansible.builtin.import_role: ansible.builtin.import_role:
name: uumas.general.vhost name: uumas.general.vhost

View File

@@ -1,26 +1,25 @@
--- ---
- name: Socat socket for {{ service_name }} - name: Socat socket for {{ socat_service_name }}
ansible.builtin.template: ansible.builtin.template:
src: socat.socket.j2 src: socat.socket.j2
dest: /etc/systemd/system/{{ service_name }}-socat.socket dest: /etc/systemd/system/{{ socat_service_name }}-socat.socket
mode: "0644" mode: "0644"
notify: Restart socat socket for {{ service_name }} notify: Restart socat socket for {{ socat_service_name }}
- name: Socat container for {{ service_name }} - name: Socat container for {{ socat_service_name }}
ansible.builtin.import_role: ansible.builtin.import_role:
name: container name: container
vars: vars:
container_name: "{{ service_name }}-socat" container_name: "{{ socat_service_name }}-socat"
container_image: "docker.io/alpine/socat:latest" container_image: "docker.io/alpine/socat:latest"
container_command: container_command:
- "ACCEPT-FD:3,fork" - "ACCEPT-FD:3,fork"
- "TCP:{{ service_name }}:{{ service_container_http_port }}" - "TCP:{{ socat_service_name }}:{{ socat_target_http_port }}"
container_user: nobody container_user: nobody
container_networks: container_networks:
- "{{ service_name }}" - "{{ socat_service_name }}"
container_requires: container_requires:
- "{{ service_name }}-socat.socket" - "{{ socat_service_name }}-socat.socket"
- "{{ service_name }}.service" - "{{ socat_service_name }}.service"
container_auto_start: false container_auto_start: false
container_auto_update: "{{ service_auto_update }}" container_auto_update: "{{ service_auto_update }}"

View File

@@ -11,10 +11,17 @@
state: directory state: directory
mode: "0700" mode: "0700"
- name: Create service template mount directories
ansible.builtin.file:
path: "{{ _service_host_directory }}/mounts/{{ item }}"
state: directory
mode: "0700"
loop: "{{ _service_all_template_mount_directories }}"
- name: Template files for template mounts - name: Template files for template mounts
ansible.builtin.template: ansible.builtin.template:
src: "{{ item[0].source }}" src: "{{ item[0].source }}"
dest: "{{ item[1].source }}" dest: "{{ item[1] }}"
mode: "0644" mode: "0644"
notify: "Restart container service {{ service_name }}" notify: Restart container service {{ service_name }}
loop: "{{ _service_template_mounts | zip(_service_container_template_mounts) }}" loop: "{{ _service_all_template_mounts | zip(_service_all_template_mount_host_files) }}"

View File

@@ -1,6 +1,6 @@
# {{ ansible_managed }} # {{ ansible_managed }}
[Unit] [Unit]
Description={{ service_name }} socat socket Description={{ socat_service_name }} socat socket
[Socket] [Socket]
ListenStream=/run/{{ service_name }}-socat.sock ListenStream=/run/{{ socat_service_name }}-socat.sock

View File

@@ -10,7 +10,7 @@ _service_container_requires: >-
_service_container_wants: >- _service_container_wants: >-
{{ {{
service_wants service_wants
+ ([service_name + '-socat.socket'] if service_domains | length > 0 else []) + ([service_name + '-socat.socket'] if service_container_http_port > 0 else [])
+ _service_additional_containers + _service_additional_containers
| map(attribute='name') | map(attribute='name')
| map('regex_replace', '$', '.service') | map('regex_replace', '$', '.service')

View File

@@ -36,3 +36,33 @@ _service_container_mounts: >-
_service_container_bind_mounts + _service_container_bind_mounts +
_service_container_template_mounts _service_container_template_mounts
}} }}
_service_all_template_mounts: >-
{{
(
_service_template_mounts +
(
_service_additional_containers |
map(attribute='mounts') |
flatten
)
) |
selectattr('type', '==', 'template') |
unique
}}
_service_all_template_mount_directories: >-
{{
_service_all_template_mounts |
map(attribute='source') |
map('dirname') |
unique |
select('!=', '')
}}
_service_all_template_mount_host_files: >-
{{
_service_all_template_mounts |
map(attribute='source') |
map('regex_replace', '\.j2$', '') |
map('regex_replace', '^', _service_host_directory ~ '/mounts/')
}}

View File

@@ -5,7 +5,7 @@ _service_proxy_headers: "{{ _service_replacement_host_header if not service_prox
_service_oauth2_proxy: "{{ service_proxy_auth_type == 'oauth2-proxy' }}" _service_oauth2_proxy: "{{ service_proxy_auth_type == 'oauth2-proxy' }}"
_service_oauth2_socket: >- _service_oauth2_socket: >-
{{ '/run/oauth2-proxy-socat.sock' if _service_oauth2_proxy else '' }} {{ '/run/' ~ service_name ~ '-oauth2-proxy-socat.sock' if _service_oauth2_proxy else '' }}
_service_oauth2_proxy_location: _service_oauth2_proxy_location:
path: /oauth2/* path: /oauth2/*
proxy_target_socket: "{{ _service_oauth2_socket }}" proxy_target_socket: "{{ _service_oauth2_socket }}"

View File

@@ -72,3 +72,21 @@
matrix_authentication_service_upstream_oauth2_scope: "{{ synapse_oidc_provider_scopes | join(' ') }}" matrix_authentication_service_upstream_oauth2_scope: "{{ synapse_oidc_provider_scopes | join(' ') }}"
matrix_authentication_service_upstream_oauth2_claims_imports: "{{ synapse_oidc_provider_mas_claims_imports }}" matrix_authentication_service_upstream_oauth2_claims_imports: "{{ synapse_oidc_provider_mas_claims_imports }}"
matrix_authentication_service_upstream_oauth2_human_name: "{{ synapse_oidc_provider_name }}" matrix_authentication_service_upstream_oauth2_human_name: "{{ synapse_oidc_provider_name }}"
- name: Reverse proxy synapse federation
ansible.builtin.import_role:
name: uumas.general.vhost
vars:
vhost_type: reverse_proxy
vhost_id: synapse-federation
vhost_domains:
- "{{ synapse_external_domain }}:8448"
vhost_proxy_target_netproto: unix
vhost_proxy_target_socket: "/run/synapse-socat.sock"
- name: Open port for synapse federation
ansible.posix.firewalld:
service: matrix
state: enabled
permanent: true
immediate: true

View File

@@ -4,4 +4,4 @@
name: "{{ volume_name }}-volume.service" name: "{{ volume_name }}-volume.service"
state: restarted state: restarted
daemon_reload: true daemon_reload: true
ignore_errors: '{{ ansible_check_mode }}' ignore_errors: "{{ ansible_check_mode }}"