From 9acd6bd73dedea1e97f9e4b20bb9282da7f8ea8f Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Thu, 11 Dec 2025 13:32:55 +0100 Subject: [PATCH 1/7] Add myaccessid proxy --- provision.yml | 1 + roles/midproxy/defaults/main.yml | 8 ++ roles/midproxy/files/internal_attributes.yaml | 27 +++++++ .../plugins/backends/openid_backend.yaml | 14 ++++ .../files/plugins/backends/saml2_backend.yaml | 1 + .../plugins/frontends/ping_frontend.yaml | 3 + .../plugins/frontends/saml2_frontend.yaml | 63 ++++++++++++++++ .../microservices/static_attributes.yaml | 5 ++ roles/midproxy/files/proxy_conf.yaml | 73 +++++++++++++++++++ roles/midproxy/tasks/main.yml | 56 ++++++++++++++ 10 files changed, 251 insertions(+) create mode 100644 roles/midproxy/defaults/main.yml create mode 100644 roles/midproxy/files/internal_attributes.yaml create mode 100644 roles/midproxy/files/plugins/backends/openid_backend.yaml create mode 100644 roles/midproxy/files/plugins/backends/saml2_backend.yaml create mode 100644 roles/midproxy/files/plugins/frontends/ping_frontend.yaml create mode 100644 roles/midproxy/files/plugins/frontends/saml2_frontend.yaml create mode 100644 roles/midproxy/files/plugins/microservices/static_attributes.yaml create mode 100644 roles/midproxy/files/proxy_conf.yaml create mode 100644 roles/midproxy/tasks/main.yml diff --git a/provision.yml b/provision.yml index be6d8fbf0..9ec706183 100644 --- a/provision.yml +++ b/provision.yml @@ -126,6 +126,7 @@ - { role: lifecycle, tags: ["lifecycle"] } - { role: stepuptiqr, tags: ['stepuptiqr' , 'stepup'] } - { role: openaccess, tags: ['openaccess' ] } + - { role: midproxy, tags: ['midproxy', 'myaccessid' ] } - hosts: docker_apps2 become: true diff --git a/roles/midproxy/defaults/main.yml b/roles/midproxy/defaults/main.yml new file mode 100644 index 000000000..3522fcb47 --- /dev/null +++ b/roles/midproxy/defaults/main.yml @@ -0,0 +1,8 @@ +--- +midproxy: + satosa_version: 8 + state_encryption_key: 'secret' + issuer: 'issuer' + client_id: 'client' + client_secret: 'secret' + sp_metadata: 'eb-metadata.xml' diff --git a/roles/midproxy/files/internal_attributes.yaml b/roles/midproxy/files/internal_attributes.yaml new file mode 100644 index 000000000..f03873371 --- /dev/null +++ b/roles/midproxy/files/internal_attributes.yaml @@ -0,0 +1,27 @@ +attributes: + displayname: + openid: [name] + saml: [displayName] + edupersontargetedid: + openid: [sub] + saml: [eduPersonTargetedID] + givenname: + openid: [given_name] + saml: [givenName] + mail: + openid: [email] + saml: [email, emailAddress, mail] + name: + openid: [name] + saml: [cn] + surname: + openid: [family_name] + saml: [sn, surname] + uid: + openid: [sub] + saml: [uid] + schachomeorganization: + openid: [schac_home_organization] + saml: [schacHomeOrganization] +user_id_from_attrs: [edupersontargetedid] +user_id_to_attr: edupersontargetedid diff --git a/roles/midproxy/files/plugins/backends/openid_backend.yaml b/roles/midproxy/files/plugins/backends/openid_backend.yaml new file mode 100644 index 000000000..cb78fcccd --- /dev/null +++ b/roles/midproxy/files/plugins/backends/openid_backend.yaml @@ -0,0 +1,14 @@ +module: satosa.backends.openid_connect.OpenIDConnectBackend +name: myaccessid +config: + provider_metadata: + issuer: !ENV SATOSA_ISSUER + client: + verify_ssl: yes + auth_req_params: + response_type: code + scope: [openid, profile, email, schac_home_organization] + client_metadata: + client_id: !ENV SATOSA_CLIENT_ID + client_secret: !ENV SATOSA_CLIENT_SECRET + redirect_uris: [/] diff --git a/roles/midproxy/files/plugins/backends/saml2_backend.yaml b/roles/midproxy/files/plugins/backends/saml2_backend.yaml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/midproxy/files/plugins/backends/saml2_backend.yaml @@ -0,0 +1 @@ +--- diff --git a/roles/midproxy/files/plugins/frontends/ping_frontend.yaml b/roles/midproxy/files/plugins/frontends/ping_frontend.yaml new file mode 100644 index 000000000..c09b218b6 --- /dev/null +++ b/roles/midproxy/files/plugins/frontends/ping_frontend.yaml @@ -0,0 +1,3 @@ +module: satosa.frontends.ping.PingFrontend +name: ping +config: null diff --git a/roles/midproxy/files/plugins/frontends/saml2_frontend.yaml b/roles/midproxy/files/plugins/frontends/saml2_frontend.yaml new file mode 100644 index 000000000..059b5bc60 --- /dev/null +++ b/roles/midproxy/files/plugins/frontends/saml2_frontend.yaml @@ -0,0 +1,63 @@ +module: satosa.frontends.saml2.SAMLFrontend +name: idp +config: + #acr_mapping: + # "": "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" + # "https://accounts.google.com": "http://eidas.europa.eu/LoA/low" + + endpoints: + single_sign_on_service: + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST': sso/post + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect': sso/redirect + + # If configured and not false or empty the common domain cookie _saml_idp will be set + # with or have appended the IdP used for authentication. The default is not to set the + # cookie. If the value is a dictionary with key 'domain' then the domain for the cookie + # will be set to the value for the 'domain' key. If no 'domain' is set then the domain + # from the BASE defined for the proxy will be used. + #common_domain_cookie: + # domain: .example.com + + entityid_endpoint: true + enable_metadata_reload: no + + idp_config: + organization: {display_name: SURF, name: SURF, url: 'https://www.surf.nl/'} + contact_person: + - {contact_type: technical, email_address: 'mailto:sram-beheer@surf.nl', given_name: Technical} + - {contact_type: support, email_address: 'mailto:sram-beheer@surf.nl', given_name: Support} + - {contact_type: other, email_address: 'mailto:sram-beheer@surf.nl', given_name: Security, extension_attributes: {'xmlns:remd': 'http://refeds.org/metadata', 'remd:contactType': 'http://refeds.org/metadata/contactType/security'}} + key_file: frontend.key + cert_file: frontend.crt + metadata: + # remote: + # - url: https://engine.test2.surfconext.nl/authentication/sp/metadata + # cert: null + local: [!ENV SATOSA_SP_METADATA] + entityid: //proxy.xml + accepted_time_diff: 60 + # attribute_map_dir: plugins/attribute-maps + service: + idp: + endpoints: + single_sign_on_service: [] + name: Proxy IdP + ui_info: + display_name: + - lang: en + text: "MyAccessID proxy" + description: + - lang: en + text: "MyAccessID proxy" + keywords: + - lang: en + text: ["MyAccessID", "proxy"] + name_id_format: ['urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'] + policy: + default: + fail_on_missing_requested: false + # name_form: urn:oasis:names:tc:SAML:2.0:attrname-format:basic + # attribute_restrictions: null + # lifetime: {minutes: 15} + # encrypt_assertion: false + # encrypted_advice_attributes: false diff --git a/roles/midproxy/files/plugins/microservices/static_attributes.yaml b/roles/midproxy/files/plugins/microservices/static_attributes.yaml new file mode 100644 index 000000000..72e25bb58 --- /dev/null +++ b/roles/midproxy/files/plugins/microservices/static_attributes.yaml @@ -0,0 +1,5 @@ +module: satosa.micro_services.attribute_modifications.AddStaticAttributes +name: AddAttributes +config: + static_attributes: + schachomeorganization: 'myaccessid.org' diff --git a/roles/midproxy/files/proxy_conf.yaml b/roles/midproxy/files/proxy_conf.yaml new file mode 100644 index 000000000..550f56217 --- /dev/null +++ b/roles/midproxy/files/proxy_conf.yaml @@ -0,0 +1,73 @@ +# BASE: https://example.com +BASE: !ENV SATOSA_BASE + +COOKIE_STATE_NAME: "SATOSA_STATE" +CONTEXT_STATE_DELETE: yes +#STATE_ENCRYPTION_KEY: "asdASD123" + +cookies_samesite_compat: + - ["SATOSA_STATE", "SATOSA_STATE_LEGACY"] + +INTERNAL_ATTRIBUTES: "internal_attributes.yaml" + +BACKEND_MODULES: + - "plugins/backends/openid_backend.yaml" + +FRONTEND_MODULES: + - "plugins/frontends/saml2_frontend.yaml" + - "plugins/frontends/ping_frontend.yaml" + +MICRO_SERVICES: + - "plugins/microservices/static_attributes.yaml" + +LOGGING: + version: 1 + formatters: + simple: + format: "[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s" + handlers: + stdout: + class: logging.StreamHandler + stream: "ext://sys.stdout" + level: DEBUG + formatter: simple + syslog: + class: logging.handlers.SysLogHandler + address: "/dev/log" + level: DEBUG + formatter: simple + debug_file: + class: logging.FileHandler + filename: satosa-debug.log + encoding: utf8 + level: DEBUG + formatter: simple + error_file: + class: logging.FileHandler + filename: satosa-error.log + encoding: utf8 + level: ERROR + formatter: simple + info_file: + class: logging.handlers.RotatingFileHandler + filename: satosa-info.log + encoding: utf8 + maxBytes: 10485760 # 10MB + backupCount: 20 + level: INFO + formatter: simple + loggers: + satosa: + level: DEBUG + saml2: + level: DEBUG + oidcendpoint: + level: DEBUG + pyop: + level: DEBUG + oic: + level: DEBUG + root: + level: DEBUG + handlers: + - stdout diff --git a/roles/midproxy/tasks/main.yml b/roles/midproxy/tasks/main.yml new file mode 100644 index 000000000..eb7bb93a4 --- /dev/null +++ b/roles/midproxy/tasks/main.yml @@ -0,0 +1,56 @@ +--- +- name: Create directory to keep configfile + ansible.builtin.file: + dest: "/opt/openconext/midproxy" + state: directory + # owner: root + # group: root + # mode: "0770" + +- name: Copy EB SP metadata + ansible.builtin.copy: + src: "{{ inventory_dir }}/files/midproxy/{{ midproxy.sp_metadata }}" + dest: "/opt/openconext/midproxy/{{ midproxy.sp_metadata }}" + # owner: "root" + # group: root + # mode: "0740" + +- name: Copy SATOSA conf files + ansible.builtin.copy: + src: "{{ item }}" + dest: "/opt/openconext/midproxy/{{ item }}" + with_items: + - internal_attributes.yaml + - proxy_config.yaml + - plugins + +- name: Create the SATOSA container + community.docker.docker_container: + name: midproxy + image: satosa:{{ midproxy.satosa_version }} + pull: true + restart_policy: "always" + state: started + networks: + - name: "loadbalancer" + env: + SATOSA_BASE: 'https://midproxy.{{ openconextaccess_base_domain }}' + SATOSA_STATE_ENCRYPTION_KEY: '{{ midproxy.state_encryption_key }}' + SATOSA_ISSUER: '{{ midproxy.issuer }}' + SATOSA_CLIENT_ID: '{{ midproxy.client_id }}' + SATOSA_CLIENT_SECRET: '{{ midproxy.client_secret }}' + SATOSA_SP_METADATA: '{{ midproxy.sp_metadata }}' + # curl is not availavble in the minimized satosa image + # so this healthcheck won't work + # healthcheck: + # test: ["CMD", "curl", "--fail" , "http://localhost" ] + # interval: 10s + # timeout: 10s + # retries: 3 + # start_period: 10s + volumes: + - /opt/openconext/midproxy:/etc/satosa + labels: + traefik.http.routers.midproxy.rule: "Host(`midproxy.{{ openconextaccess_base_domain }}`)" + traefik.http.routers.midproxy.tls: "true" + traefik.enable: "true" From b14fcf5335e830de8c80d4afcb3a479d65870422 Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Thu, 11 Dec 2025 13:46:02 +0100 Subject: [PATCH 2/7] Better secrets --- roles/midproxy/tasks/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/midproxy/tasks/main.yml b/roles/midproxy/tasks/main.yml index eb7bb93a4..133069e67 100644 --- a/roles/midproxy/tasks/main.yml +++ b/roles/midproxy/tasks/main.yml @@ -36,10 +36,10 @@ env: SATOSA_BASE: 'https://midproxy.{{ openconextaccess_base_domain }}' SATOSA_STATE_ENCRYPTION_KEY: '{{ midproxy.state_encryption_key }}' - SATOSA_ISSUER: '{{ midproxy.issuer }}' - SATOSA_CLIENT_ID: '{{ midproxy.client_id }}' - SATOSA_CLIENT_SECRET: '{{ midproxy.client_secret }}' SATOSA_SP_METADATA: '{{ midproxy.sp_metadata }}' + SATOSA_ISSUER: '{{ midproxy.issuer }}' + SATOSA_CLIENT_ID: '{{ midproxy_client_id }}' + SATOSA_CLIENT_SECRET: '{{ midproxy_client_secret }}' # curl is not availavble in the minimized satosa image # so this healthcheck won't work # healthcheck: From f1e153b0c522e6e7bcbbd210f7730ac4ff98af03 Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Thu, 11 Dec 2025 13:52:29 +0100 Subject: [PATCH 3/7] Use /opt/sram config location --- roles/midproxy/tasks/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/midproxy/tasks/main.yml b/roles/midproxy/tasks/main.yml index 133069e67..5a7b8c0db 100644 --- a/roles/midproxy/tasks/main.yml +++ b/roles/midproxy/tasks/main.yml @@ -1,7 +1,7 @@ --- - name: Create directory to keep configfile ansible.builtin.file: - dest: "/opt/openconext/midproxy" + dest: "/opt/sram/midproxy" state: directory # owner: root # group: root @@ -10,7 +10,7 @@ - name: Copy EB SP metadata ansible.builtin.copy: src: "{{ inventory_dir }}/files/midproxy/{{ midproxy.sp_metadata }}" - dest: "/opt/openconext/midproxy/{{ midproxy.sp_metadata }}" + dest: "/opt/sram/midproxy/{{ midproxy.sp_metadata }}" # owner: "root" # group: root # mode: "0740" @@ -18,10 +18,10 @@ - name: Copy SATOSA conf files ansible.builtin.copy: src: "{{ item }}" - dest: "/opt/openconext/midproxy/{{ item }}" + dest: "/opt/sram/midproxy/{{ item }}" with_items: - internal_attributes.yaml - - proxy_config.yaml + - proxy_conf.yaml - plugins - name: Create the SATOSA container @@ -49,7 +49,7 @@ # retries: 3 # start_period: 10s volumes: - - /opt/openconext/midproxy:/etc/satosa + - /opt/sram/midproxy:/etc/satosa labels: traefik.http.routers.midproxy.rule: "Host(`midproxy.{{ openconextaccess_base_domain }}`)" traefik.http.routers.midproxy.tls: "true" From 97bf442c4ac6c0ca902dac46557e4fb666c527f5 Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Thu, 11 Dec 2025 14:03:43 +0100 Subject: [PATCH 4/7] Chown to satosa user --- roles/midproxy/tasks/main.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/roles/midproxy/tasks/main.yml b/roles/midproxy/tasks/main.yml index 5a7b8c0db..4969e56bb 100644 --- a/roles/midproxy/tasks/main.yml +++ b/roles/midproxy/tasks/main.yml @@ -3,22 +3,24 @@ ansible.builtin.file: dest: "/opt/sram/midproxy" state: directory - # owner: root - # group: root - # mode: "0770" + owner: 1000 + group: 1000 + mode: "0770" - name: Copy EB SP metadata ansible.builtin.copy: src: "{{ inventory_dir }}/files/midproxy/{{ midproxy.sp_metadata }}" dest: "/opt/sram/midproxy/{{ midproxy.sp_metadata }}" - # owner: "root" - # group: root - # mode: "0740" + owner: 1000 + group: 1000 + mode: "0740" - name: Copy SATOSA conf files ansible.builtin.copy: src: "{{ item }}" dest: "/opt/sram/midproxy/{{ item }}" + owner: 1000 + group: 1000 with_items: - internal_attributes.yaml - proxy_conf.yaml @@ -35,7 +37,7 @@ - name: "loadbalancer" env: SATOSA_BASE: 'https://midproxy.{{ openconextaccess_base_domain }}' - SATOSA_STATE_ENCRYPTION_KEY: '{{ midproxy.state_encryption_key }}' + SATOSA_STATE_ENCRYPTION_KEY: '{{ midproxy_state_encryption_key }}' SATOSA_SP_METADATA: '{{ midproxy.sp_metadata }}' SATOSA_ISSUER: '{{ midproxy.issuer }}' SATOSA_CLIENT_ID: '{{ midproxy_client_id }}' From d5b9ecb56644a43abc40073d37b2f35f32bf9b01 Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Thu, 11 Dec 2025 14:23:08 +0100 Subject: [PATCH 5/7] Fix recursive directory copy --- roles/midproxy/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/midproxy/tasks/main.yml b/roles/midproxy/tasks/main.yml index 4969e56bb..69e072ce4 100644 --- a/roles/midproxy/tasks/main.yml +++ b/roles/midproxy/tasks/main.yml @@ -24,7 +24,7 @@ with_items: - internal_attributes.yaml - proxy_conf.yaml - - plugins + - plugins/ - name: Create the SATOSA container community.docker.docker_container: From 81009cb2a93e09ac99bd7a906623cd96d8ebacf1 Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Thu, 11 Dec 2025 14:42:09 +0100 Subject: [PATCH 6/7] WIP --- roles/midproxy/tasks/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/roles/midproxy/tasks/main.yml b/roles/midproxy/tasks/main.yml index 69e072ce4..346f56e6e 100644 --- a/roles/midproxy/tasks/main.yml +++ b/roles/midproxy/tasks/main.yml @@ -42,6 +42,12 @@ SATOSA_ISSUER: '{{ midproxy.issuer }}' SATOSA_CLIENT_ID: '{{ midproxy_client_id }}' SATOSA_CLIENT_SECRET: '{{ midproxy_client_secret }}' + volumes: + - /opt/sram/midproxy:/etc/satosa + labels: + traefik.http.routers.midproxy.rule: "Host(`midproxy.{{ openconextaccess_base_domain }}`)" + traefik.http.routers.midproxy.tls: "true" + traefik.enable: "true" # curl is not availavble in the minimized satosa image # so this healthcheck won't work # healthcheck: @@ -50,9 +56,3 @@ # timeout: 10s # retries: 3 # start_period: 10s - volumes: - - /opt/sram/midproxy:/etc/satosa - labels: - traefik.http.routers.midproxy.rule: "Host(`midproxy.{{ openconextaccess_base_domain }}`)" - traefik.http.routers.midproxy.tls: "true" - traefik.enable: "true" From 267dc7b93fee96af665b7cef2bcc8555eecccffa Mon Sep 17 00:00:00 2001 From: Martin van Es Date: Fri, 12 Dec 2025 11:49:27 +0100 Subject: [PATCH 7/7] loglevel INFO --- roles/midproxy/files/proxy_conf.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/roles/midproxy/files/proxy_conf.yaml b/roles/midproxy/files/proxy_conf.yaml index 550f56217..49594d6aa 100644 --- a/roles/midproxy/files/proxy_conf.yaml +++ b/roles/midproxy/files/proxy_conf.yaml @@ -29,18 +29,18 @@ LOGGING: stdout: class: logging.StreamHandler stream: "ext://sys.stdout" - level: DEBUG + level: INFO formatter: simple syslog: class: logging.handlers.SysLogHandler address: "/dev/log" - level: DEBUG + level: INFO formatter: simple debug_file: class: logging.FileHandler filename: satosa-debug.log encoding: utf8 - level: DEBUG + level: INFO formatter: simple error_file: class: logging.FileHandler @@ -58,16 +58,16 @@ LOGGING: formatter: simple loggers: satosa: - level: DEBUG + level: INFO saml2: - level: DEBUG + level: INFO oidcendpoint: - level: DEBUG + level: INFO pyop: - level: DEBUG + level: INFO oic: - level: DEBUG + level: INFO root: - level: DEBUG + level: INFO handlers: - stdout