Compare commits

...

21 Commits

Author SHA1 Message Date
Jonathan Perret 8f9a9ed1f0 temporary enable debug logs in production 2025-03-05 17:32:56 +01:00
rouja a6e01c071e Merge pull request #21 from numerique-gouv/add-pdbs
🔧(helm) add pdbs to deployements
2025-02-10 17:24:10 +01:00
Jacques ROUSSEL 5a0f2da202 🔧(helm) add pdbs to deployements
In order to avoid a service interruption during a Kubernetes
(k8s)upgrade, we add a Pod Disruption Budget (PDB) to deployments.
2025-02-10 17:19:08 +01:00
rouja 3b2d50d657 Merge pull request #20 from numerique-gouv/fix-issuer
fix letsencrypt issuer for new preprod
2025-02-07 11:53:59 +01:00
Jacques ROUSSEL 52d7de305c 🔧(helm) change letsencrypt issuer
The name of the cluster issuer on the new preprod is 'letsencrypt,' so I
adjusted it.
2025-02-07 10:49:36 +01:00
Jonathan Perret 64a0d4dd3d Merge pull request #19 from numerique-gouv/improve-helm 2024-10-02 10:46:04 +02:00
Jacques ROUSSEL ffbd161e29 (ci) add helmfile linter
Add a github job to run helmfile linter on PR
2024-09-24 17:11:13 +02:00
Jonathan Perret ba1c14291d Merge pull request #17 from numerique-gouv/add-architecture-doc
📝(architecture) add first architecture doc
2024-09-21 12:21:01 +02:00
Jonathan Perret 4c4ccc88ba 📝(architecture) add first architecture doc
This gives an overview and the detail of the workings of OIDC2FER.
2024-09-18 19:31:33 +02:00
Jonathan Perret c1b33453c3 Deploy release v1.0.4 to production. 2024-09-11 12:43:17 +02:00
Jonathan Perret 6cede0a7f2 v1.0.4 release 2024-09-11 11:00:09 +02:00
Jonathan Perret 3b518b9b3a Merge pull request #15 from numerique-gouv/serve-static-assets
(static) add static frontend to serve assets
2024-09-11 10:49:04 +02:00
Jonathan Perret 039d9a12cc (static) add static file serving
We needed a way to serve a handful of static assets, starting with
the ProConnect logo to be embedded in IdP pages.
2024-09-11 10:44:11 +02:00
Jonathan Perret 6424679b85 Set discovery URL to dedicated WAYF 2024-09-05 19:11:57 +02:00
Jonathan Perret 30c91e2345 Add missing slash to discovery URL
This saves one redirect when accessing the discovery service.
2024-09-04 20:05:06 +02:00
Jonathan Perret ad726a92ce Add missing info about "production" tag to deployment instructions 2024-09-02 17:42:42 +02:00
Jonathan Perret 7cc8fc18a2 Deploy release v1.0.3 to production. 2024-09-02 17:18:00 +02:00
Jonathan Perret 17289b1040 v1.0.3 release 2024-09-02 17:09:56 +02:00
Jonathan Perret 0580ec6d7e Merge pull request #14 from numerique-gouv/fix-saml-signature
Upgrade SAML signature algorithm for interoperability with RENATER Access Check
2024-09-02 16:26:07 +02:00
Jonathan Perret 4b5bd5757c 🔒️(saml) set SAML signing algorithm to use SHA256
It turns out the RENATER AccessCheck IdP rejects AuthnRequests signed
with the default SHA1-based SignatureMethod.
2024-08-29 20:34:36 +02:00
Jonathan Perret 61680de401 Deploy 1.0.2 to outscale-production 2024-07-22 20:55:08 +02:00
18 changed files with 201 additions and 7 deletions
+22
View File
@@ -0,0 +1,22 @@
name: Helmfile lint
run-name: Helmfile lint
on:
pull_request:
branches:
- 'main'
jobs:
helmfile-lint:
runs-on: ubuntu-latest
container:
image: ghcr.io/helmfile/helmfile:latest
steps:
-
uses: numerique-gouv/action-helmfile-lint@main
with:
app-id: ${{ secrets.APP_ID }}
age-key: ${{ secrets.SOPS_PRIVATE }}
private-key: ${{ secrets.PRIVATE_KEY }}
helmfile-src: "src/helm"
repositories: "oidc2fer,secrets"
+6
View File
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.4] - 2024-09-11
- serve static files
## [1.0.3] - 2024-09-02
- set SAML signing algorithm to use SHA256 for compatibility with AccessCheck
## [1.0.2] - 2024-07-22
- check the scope of returned eduPersonPrincipalNames
- require "employee" value in eduPersonAffiliation
+1 -1
View File
@@ -38,7 +38,7 @@ RUN mkdir -p /usr/local/etc/gunicorn
COPY docker/files/usr/local/etc/gunicorn/satosa.py /usr/local/etc/gunicorn/satosa.py
# The default command runs gunicorn WSGI server in satosa's main module
CMD ["gunicorn", "-c", "/usr/local/etc/gunicorn/satosa.py", "satosa.wsgi:app"]
CMD ["gunicorn", "-c", "/usr/local/etc/gunicorn/satosa.py"]
# ---- Development image ----
FROM common as development
+16
View File
@@ -47,6 +47,22 @@ Finally, you can check all available Make rules using:
$ make help
```
## Creating a release
1. Update `CHANGELOG.md` to change the `Unreleased` header to the new version
number and date.
2. Commit and push to `main`.
3. Create a `vX.Y.Z` tag from `main` and push it.
## Deploying a release to production (DINUM instance)
1. Make sure the release you want to deploy has been built and appears on
https://hub.docker.com/r/lasuite/oidc2fer/tags .
2. Edit `image/tag` at the top of
`src/helm/env.d/outscale-production/values.oidc2fer.yaml.gotmpl`.
3. Commit and push to `main`.
4. Update the `production` tag and push it.
## Contributing
This project is intended to be community-driven, so please, do not hesitate to
@@ -63,6 +63,7 @@ class DefaultJSONFormatter(json_log_formatter.JSONFormatter):
bind = ["0.0.0.0:8000"]
name = "satosa"
python_path = "/app"
wsgi_app = "oidc2fer.wsgi:app"
# Run
graceful_timeout = 90
+93
View File
@@ -0,0 +1,93 @@
# Principe de fonctionnement de la passerelle ProConnect vers RENATER (`OIDC2FER`)
## Vue d'ensemble
Ce premier schéma donne un aperçu des échanges entre :
* un Fournisseur de Service ProConnecté (ex. https://pad.numerique.gouv.fr) ;
* le service ProConnect (hébergé sur `https://auth.agentconnect.gouv.fr`) ;
* la passerelle `OIDC2FER` (hébergé sur `https://renater.agentconnect.gouv.fr`) ;
* le service de _discovery_ ou _Where Are You From (WAYF)_ RENATER qui permet à l'utilisateur de choisir son établissement de rattachement, hébergé sur https://discovery.renater.fr/agentconnect/ ;
* le serveur d'identité SAML de l'établissement sélectionné (par exemple, https://cas.inria.fr).
``` mermaid
sequenceDiagram
participant FS as Fournisseur<br>de Service
participant ProConnect
box LightYellow
participant OIDC2FER
end
participant WAYF as WAYF<br>RENATER
participant IdP as IdP SAML
FS->>ProConnect: OIDC auth request
ProConnect->>OIDC2FER: OIDC auth request
OIDC2FER->>WAYF: discovery request
WAYF->>OIDC2FER: IdP entityID
OIDC2FER->>IdP: SAML AuthnRequest
IdP->>OIDC2FER: SAML Assertion
OIDC2FER->>ProConnect: OIDC tokens+userinfo
ProConnect->>FS: OIDC tokens+userinfo
```
## Détail des échanges
Noter que le schéma précédent ne reflète pas le détail des échanges entre l'utilisateur, son navigateur (qu'il est utile de distinguer pour illustrer que plusieurs échanges se font sans intervention humaine), et les différents services mentionnés. En voici une version exhaustive :
``` mermaid
sequenceDiagram
actor Utilisateur
participant Navigateur
participant FS as Fournisseur<br>de Service
participant ProConnect
box LightYellow
participant OIDC2FER
end
participant WAYF as WAYF<br>RENATER
participant IdP SAML
Utilisateur->>Navigateur: Saisie/clic URL FS
Navigateur->>FS: Requête d'une page du FS
opt si pas de session FS ouverte
FS->>Utilisateur: Présentation page d'accueil avec bouton ProConnect
Utilisateur->>FS: Clic bouton ProConnect
FS->>Navigateur: Redirection OIDC vers ProConnect avec state, nonce
Navigateur->>ProConnect: Requête GET avec state, nonce
opt si pas de session ProConnect ouverte
ProConnect->>Utilisateur: Présentation mire ProConnect
Utilisateur->>ProConnect: Clic bouton RENATER, ou saisie "robert@univ-exemple.fr"
ProConnect->>Navigateur: Redirection OIDC vers OIDC2FER avec state, nonce
Navigateur->>OIDC2FER: Requête GET avec state, nonce
OIDC2FER->>Navigateur: Redirection vers WAYF
Navigateur->>WAYF: Requête GET
opt si pas de préselection enregistrée dans le WAYF
WAYF->>Utilisateur: Présentation liste d'établissements autorisés
Utilisateur->>WAYF: Choix d'un établissement
end
WAYF->>Navigateur: Redirection vers OIDC2FER avec entityID IdP
Navigateur->>OIDC2FER: Requête GET avec entityID IdP
OIDC2FER->>Navigateur: Redirection vers IdP avec AuthnRequest SAML dans l'URL
Navigateur->>IdP SAML: Requête GET avec AuthnRequest SAML dans l'URL
opt si pas de session IdP ouverte
IdP SAML->>Utilisateur: Présentation mire de connexion IdP
Utilisateur->>IdP SAML: Saisie identifiants de connexion
end
IdP SAML->>Navigateur: Page avec formulaire contenant assertion SAML
Navigateur->>OIDC2FER: Requête POST avec assertion SAML
Note over OIDC2FER: Validation<br>eduPersonAffiliation
Note over OIDC2FER: Conversion attributs<br>SAML vers OIDC
OIDC2FER->>Navigateur: Redirection vers callback OIDC ProConnect avec authorization_code
Navigateur->>ProConnect: Requête GET avec authorization_code
ProConnect->>OIDC2FER: Demande tokens avec authorization_code
OIDC2FER->>ProConnect: Tokens OIDC
ProConnect->>OIDC2FER: Demande userinfo avec accessToken
OIDC2FER->>ProConnect: userinfo
end
ProConnect->>Navigateur: Redirection vers callback OIDC FS avec authorization_code
Navigateur->>FS: Requête GET avec authorization_code
FS->>ProConnect: Demande tokens avec authorization_code
ProConnect->>FS: Tokens OIDC
FS->>ProConnect: Demande userinfo avec accessToken
ProConnect->>FS: userinfo
end
FS->>Utilisateur: Contenu du service
```
+1 -1
Submodule secrets updated: 647b88689c...b0d485544d
@@ -1,7 +1,7 @@
image:
repository: lasuite/oidc2fer
pullPolicy: Always
tag: "v1.0.1"
tag: "v1.0.4"
satosa:
replicas: 2
@@ -9,9 +9,9 @@ satosa:
BASE_URL: https://renater.agentconnect.gouv.fr
GUNICORN_CMD_ARGS: --workers=3
LOG_LEVEL: info
LOG_LEVEL: debug
SAML2_DISCOVERY_URL: https://discovery.renater.fr/renater
SAML2_DISCOVERY_URL: https://discovery.renater.fr/agentconnect/
SAML2_METADATA_URL: https://pub.federation.renater.fr/metadata/renater/main/main-idps-renater-metadata.xml
SAML2_ENTITY_ID: https://renater.agentconnect.gouv.fr/Saml2/proxy_saml2_backend.xml
@@ -28,5 +28,5 @@ ingress:
host: oidc2fer-staging.beta.numerique.gouv.fr
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
@@ -82,3 +82,16 @@ spec:
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
{{ if .Values.satosa.pdb.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
spec:
maxUnavailable: 1
selector:
matchLabels:
{{- include "oidc2fer.common.selectorLabels" (list . $component) | nindent 6 }}
{{ end }}
+4
View File
@@ -52,6 +52,10 @@ ingress:
satosa:
## @param satosa.pdb.enabled Enable pdb on backend
pdb:
enabled: true
## @param satosa.command Override the satosa container command
command: []
+2 -1
View File
@@ -67,7 +67,8 @@ disable=bad-inline-option,
useless-suppression,
missing-module-docstring,
missing-class-docstring,
missing-function-docstring
missing-function-docstring,
wrong-import-order
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
+9
View File
@@ -0,0 +1,9 @@
import os
from satosa.wsgi import app as satosa_app
from whitenoise import WhiteNoise
# Wrap the SATOSA WSGI app in WhiteNoise to serve static files
app = WhiteNoise(
satosa_app, root=os.path.join(os.curdir, "static"), index_file="index.html"
)
@@ -38,6 +38,7 @@ config:
height: '200'
authn_requests_signed: true
want_response_signed: true
signing_algorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
allow_unsolicited: true
name_id_format:
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
+1
View File
@@ -27,6 +27,7 @@ dependencies = [
"gunicorn==22.0.0",
"redis==5.0.4",
"JSON-log-formatter==1.0",
"WhiteNoise==6.7.0",
]
[project.urls]
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

+9
View File
@@ -0,0 +1,9 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="1; url=https://agentconnect.gouv.fr/">
</head>
<body>
<h1>Passerelle ProConnect vers RENATER. Redirection en cours…</h1>
</body>
</html>
+8
View File
@@ -126,3 +126,11 @@ def test_agent_connect_to_renater_student_not_allowed(page: Page):
renater_test_idp(page, login="etudiant1")
expect(page.locator("body")).to_contain_text("Une erreur technique est survenue.")
@pytest.mark.skipif(
"TEST_E2E" not in os.environ, reason="Depends on app running locally"
)
def test_serve_static_assets(page: Page):
page.goto("https://satosa.traefik.me/images/logo.svg")
expect(page.locator("svg")).to_be_visible()