Skip to content

Commit 3fefe55

Browse files
authored
fix(zitadel): vendor ovhcloud saml sp metadata instead of fetching at plan time (#1799)
1 parent 24c6fba commit 3fefe55

7 files changed

Lines changed: 51 additions & 31 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://www.ovhcloud.com/eu/auth/">
3+
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
4+
<KeyDescriptor>
5+
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
6+
<X509Data>
7+
<X509Certificate>MIIFVzCCAz+gAwIBAgIUQSUwSIh9zUNgNtP/FhkGdy7bEPYwDQYJKoZIhvcNAQELBQAwOzEdMBsGA1UEAwwUYXV0aC5ldS5vdmhjbG91ZC5jb20xCzAJBgNVBAsMAlNQMQ0wCwYDVQQKDARTQU1MMB4XDTI0MDExMjE0MTYzM1oXDTM0MDEwOTE0MTYzM1owOzEdMBsGA1UEAwwUYXV0aC5ldS5vdmhjbG91ZC5jb20xCzAJBgNVBAsMAlNQMQ0wCwYDVQQKDARTQU1MMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0RWhT7fEM8NLiLeEe9Burk15IJUVHvHXJFySOr4lGhbpUWXgnRQZKP8klr3Jd9jZwv9ss+NhsbT/64lqB6WINozk11fGefdyrO6TbIioQnTOcwtF7NCTy9ypuBZiseqMxA67g6VDRqtRuZCtHVFOBJxMzux0h6sGS5t/a3aaHR+0xw9dhhHE0+sNiZUehl0BuNafoelar1nK6Q1ZfXWmoC5zJjxxJAE2DH+kNZaWOdkbPCWpD5G1maZlNL+tEFHzAAmCjj5re4C9enMs4/XPnxqS4wLzsuAEU2/7917+wdgPTpF7RHsqYgFD+gff00IkpY1+H8oqsEtf/iebIvoy0EYD0KozPnSolKNHhOEqSFcxehtCDOPdVq92Ie5FzMPLEeZoO1UvPIlKm2043BjGbNtYNBcFOTP6jdMInGau7KLXz/Bh5g/8mBI+UyCTbZaSoB1GkfzJJpP5j+VPYXcum/s/Y0AJUwNBXujQnu7EkNwQeE8QkjfrHXSC0wI6QYzpcc4DyMk1TNWg+4dn2EdU0TJS+zO/ohaAO1L1O9Pw6+JfHrXcNy5E7iPeRyMhkRMEhWyHxh6PlO7c2Hydo1WVAuV1BqQJmjMYP3D4dzcdmaZiy6JElV4fvkGBh/J3+jRGqeQtb0vplz0d3Dj5Zeto07xi79XtaItk4e9a6KPVds8CAwEAAaNTMFEwHQYDVR0OBBYEFJ/VldqCVgz9XObIdmTtzX+7qo9JMB8GA1UdIwQYMBaAFJ/VldqCVgz9XObIdmTtzX+7qo9JMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBACVM09u+blp3PDDjJsSJM0WyAq40bamTxncfyqZG1P+pN+K/Y38XU+F874FpiglFn1U1ZNekPA8HHj9SpRK1iZKqohB2r6ivwMqcwOJJM3LPNuPxs/RnNXAuup7KfnkEocnIYfad4KUr5QZoWfAyzMGiiRUF9mY4mLvRii1627XsTeQiDN2NJKvl/8FzXSWy2X61nA6kjw7erx5n6QoOprrXbG4Lmq2dRGdO3fqKtSByXrr5pLvHQgduoCtwbJn2mJHEnNSM8h7EDcszMRsgagQuUxT/XdGA8jqzs/qL38XHPxSmdaVzLO1pIxGXH5mZ+emDPGFN/Yd3WA/63qQ+Ig+ctu5gKJGDHaVLXmHE/cQXWs9tYoEen2iSL4nTf9hdH9hz7osQ1q9tNyJkHPwxYYvV9po6ui6jivd/OrasO54SzkoIEIlz0GpaZ4+sVfxWxoaHguQjmbesrppMXwdj8rc8fzKq70nMUm/T3hlehFXsBeH1lZygfKpb1EtpSbmStrQ/pY6xPB0oa4syj9kAnLfVWWsogg4RnIJ3QBZmk5qqwkf1Nq07fnXxIHRxmt5c1PS4hqvSxvIcH/Ghq0VVDZb3yMELZYJWIN20Q52A9I78yEwbjWmtGJ9oG1hRceGlWsxVhqX6Br1fHaHvkgz8HIoTM6kwPAHT+IVxnBIkKOuC</X509Certificate>
8+
</X509Data>
9+
</KeyInfo>
10+
</KeyDescriptor>
11+
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
12+
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.ovhcloud.com/eu/auth/saml/acs" index="1"></AssertionConsumerService>
13+
</SPSSODescriptor>
14+
</EntityDescriptor>

tf/deployment/modules/shared/zitadel/cloud/config.tf

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ terraform {
1313
source = "1Password/onepassword"
1414
version = "~> 2.1"
1515
}
16-
http = {
17-
source = "hashicorp/http"
18-
version = "~> 3.5"
19-
}
2016
cloudflare = {
2117
source = "cloudflare/cloudflare"
2218
version = "5.19.1"

tf/deployment/modules/shared/zitadel/cloud/project.tf

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ locals {
66
postLogoutRedirectUris = []
77
grantTypes = ["AUTHORIZATION_CODE"]
88
protocol = "oidc"
9-
metadataUrl = ""
9+
metadataFile = ""
1010
# When true, a user is granted every role they match (not just the
1111
# highest-priority one) — e.g. Outline admins land in Leadership and Team.
1212
multi_role = false
@@ -86,10 +86,15 @@ locals {
8686
roles = [{ key = "Granted", grants_to = ["yucca"] }]
8787
},
8888
{
89-
name = "OVHCloud"
90-
protocol = "saml"
91-
roles = [{ key = "ADMIN", grants_to = ["immich_admin", "yucca"] }, { key = "DEFAULT", grants_to = ["team"] }]
92-
metadataUrl = "https://auth.eu.ovhcloud.com/sso/saml/sp/metadata.xml"
89+
name = "OVHCloud"
90+
protocol = "saml"
91+
roles = [{ key = "ADMIN", grants_to = ["immich_admin", "yucca"] }, { key = "DEFAULT", grants_to = ["team"] }]
92+
# SP metadata is vendored rather than fetched at plan time: OVH gates
93+
# https://auth.eu.ovhcloud.com/sso/saml/sp/metadata.xml behind a CDN
94+
# Set-Cookie 307-redirect-to-self that the http provider (no cookie jar)
95+
# can't satisfy, so `data.http` loops to 10 redirects and fails the apply.
96+
# Re-fetch with `curl -sL -c jar -b jar <url>` if OVH rotates their SP cert.
97+
metadataFile = "ovhcloud-sp-metadata.xml"
9398
}
9499
]
95100

@@ -152,15 +157,10 @@ resource "onepassword_item" "application_client_secret" {
152157
password = each.value.client_secret
153158
}
154159

155-
data "http" "saml_sp_metadata" {
156-
for_each = { for project in local.saml_projects : project.name => project }
157-
url = each.value.metadataUrl
158-
}
159-
160160
resource "zitadel_application_saml" "applications" {
161161
for_each = { for project in local.saml_projects : project.name => project }
162162
name = upper(replace(each.value.name, "/[^a-zA-Z0-9]/", "_"))
163163
org_id = zitadel_org.immich.id
164164
project_id = zitadel_project.projects[each.key].id
165-
metadata_xml = data.http.saml_sp_metadata[each.key].response_body
165+
metadata_xml = file("${path.module}/assets/${each.value.metadataFile}")
166166
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://www.ovhcloud.com/eu/auth/">
3+
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
4+
<KeyDescriptor>
5+
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
6+
<X509Data>
7+
<X509Certificate>MIIFVzCCAz+gAwIBAgIUQSUwSIh9zUNgNtP/FhkGdy7bEPYwDQYJKoZIhvcNAQELBQAwOzEdMBsGA1UEAwwUYXV0aC5ldS5vdmhjbG91ZC5jb20xCzAJBgNVBAsMAlNQMQ0wCwYDVQQKDARTQU1MMB4XDTI0MDExMjE0MTYzM1oXDTM0MDEwOTE0MTYzM1owOzEdMBsGA1UEAwwUYXV0aC5ldS5vdmhjbG91ZC5jb20xCzAJBgNVBAsMAlNQMQ0wCwYDVQQKDARTQU1MMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0RWhT7fEM8NLiLeEe9Burk15IJUVHvHXJFySOr4lGhbpUWXgnRQZKP8klr3Jd9jZwv9ss+NhsbT/64lqB6WINozk11fGefdyrO6TbIioQnTOcwtF7NCTy9ypuBZiseqMxA67g6VDRqtRuZCtHVFOBJxMzux0h6sGS5t/a3aaHR+0xw9dhhHE0+sNiZUehl0BuNafoelar1nK6Q1ZfXWmoC5zJjxxJAE2DH+kNZaWOdkbPCWpD5G1maZlNL+tEFHzAAmCjj5re4C9enMs4/XPnxqS4wLzsuAEU2/7917+wdgPTpF7RHsqYgFD+gff00IkpY1+H8oqsEtf/iebIvoy0EYD0KozPnSolKNHhOEqSFcxehtCDOPdVq92Ie5FzMPLEeZoO1UvPIlKm2043BjGbNtYNBcFOTP6jdMInGau7KLXz/Bh5g/8mBI+UyCTbZaSoB1GkfzJJpP5j+VPYXcum/s/Y0AJUwNBXujQnu7EkNwQeE8QkjfrHXSC0wI6QYzpcc4DyMk1TNWg+4dn2EdU0TJS+zO/ohaAO1L1O9Pw6+JfHrXcNy5E7iPeRyMhkRMEhWyHxh6PlO7c2Hydo1WVAuV1BqQJmjMYP3D4dzcdmaZiy6JElV4fvkGBh/J3+jRGqeQtb0vplz0d3Dj5Zeto07xi79XtaItk4e9a6KPVds8CAwEAAaNTMFEwHQYDVR0OBBYEFJ/VldqCVgz9XObIdmTtzX+7qo9JMB8GA1UdIwQYMBaAFJ/VldqCVgz9XObIdmTtzX+7qo9JMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBACVM09u+blp3PDDjJsSJM0WyAq40bamTxncfyqZG1P+pN+K/Y38XU+F874FpiglFn1U1ZNekPA8HHj9SpRK1iZKqohB2r6ivwMqcwOJJM3LPNuPxs/RnNXAuup7KfnkEocnIYfad4KUr5QZoWfAyzMGiiRUF9mY4mLvRii1627XsTeQiDN2NJKvl/8FzXSWy2X61nA6kjw7erx5n6QoOprrXbG4Lmq2dRGdO3fqKtSByXrr5pLvHQgduoCtwbJn2mJHEnNSM8h7EDcszMRsgagQuUxT/XdGA8jqzs/qL38XHPxSmdaVzLO1pIxGXH5mZ+emDPGFN/Yd3WA/63qQ+Ig+ctu5gKJGDHaVLXmHE/cQXWs9tYoEen2iSL4nTf9hdH9hz7osQ1q9tNyJkHPwxYYvV9po6ui6jivd/OrasO54SzkoIEIlz0GpaZ4+sVfxWxoaHguQjmbesrppMXwdj8rc8fzKq70nMUm/T3hlehFXsBeH1lZygfKpb1EtpSbmStrQ/pY6xPB0oa4syj9kAnLfVWWsogg4RnIJ3QBZmk5qqwkf1Nq07fnXxIHRxmt5c1PS4hqvSxvIcH/Ghq0VVDZb3yMELZYJWIN20Q52A9I78yEwbjWmtGJ9oG1hRceGlWsxVhqX6Br1fHaHvkgz8HIoTM6kwPAHT+IVxnBIkKOuC</X509Certificate>
8+
</X509Data>
9+
</KeyInfo>
10+
</KeyDescriptor>
11+
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
12+
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.ovhcloud.com/eu/auth/saml/acs" index="1"></AssertionConsumerService>
13+
</SPSSODescriptor>
14+
</EntityDescriptor>

tf/deployment/modules/shared/zitadel/self-hosted/config.tf

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,5 @@ terraform {
1313
source = "1Password/onepassword"
1414
version = "~> 2.1"
1515
}
16-
http = {
17-
source = "hashicorp/http"
18-
version = "~> 3.5"
19-
}
2016
}
2117
}

tf/deployment/modules/shared/zitadel/self-hosted/project.tf

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ locals {
55
redirectUris = []
66
grantTypes = ["AUTHORIZATION_CODE"]
77
protocol = "oidc"
8-
metadataUrl = ""
8+
metadataFile = ""
99
}
1010
projects_data = [
1111
{
@@ -54,10 +54,15 @@ locals {
5454
redirectUris = ["https://loopdedupe.internal.immich.cloud/oauth2/callback"]
5555
},
5656
{
57-
name = "OVHCloud"
58-
protocol = "saml"
59-
roles = [{ key = "ADMIN", grants_to = ["immich_admin", "yucca"] }, { key = "DEFAULT", grants_to = ["team"] }]
60-
metadataUrl = "https://auth.eu.ovhcloud.com/sso/saml/sp/metadata.xml"
57+
name = "OVHCloud"
58+
protocol = "saml"
59+
roles = [{ key = "ADMIN", grants_to = ["immich_admin", "yucca"] }, { key = "DEFAULT", grants_to = ["team"] }]
60+
# SP metadata is vendored rather than fetched at plan time: OVH gates
61+
# https://auth.eu.ovhcloud.com/sso/saml/sp/metadata.xml behind a CDN
62+
# Set-Cookie 307-redirect-to-self that the http provider (no cookie jar)
63+
# can't satisfy, so `data.http` loops to 10 redirects and fails the apply.
64+
# Re-fetch with `curl -sL -c jar -b jar <url>` if OVH rotates their SP cert.
65+
metadataFile = "ovhcloud-sp-metadata.xml"
6166
}
6267
]
6368

@@ -119,15 +124,10 @@ resource "onepassword_item" "application_client_secret" {
119124
password = each.value.client_secret
120125
}
121126

122-
data "http" "saml_sp_metadata" {
123-
for_each = { for project in local.saml_projects : project.name => project }
124-
url = each.value.metadataUrl
125-
}
126-
127127
resource "zitadel_application_saml" "applications" {
128128
for_each = { for project in local.saml_projects : project.name => project }
129129
name = upper(replace(each.value.name, "/[^a-zA-Z0-9]/", "_"))
130130
org_id = zitadel_org.immich.id
131131
project_id = zitadel_project.projects[each.key].id
132-
metadata_xml = data.http.saml_sp_metadata[each.key].response_body
132+
metadata_xml = file("${path.module}/assets/${each.value.metadataFile}")
133133
}

tf/deployment/modules/shared/zitadel/self-hosted/terragrunt.hcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ terraform {
55
commands = get_terraform_commands_that_need_vars()
66
}
77

8-
include_in_copy = ["repo-files/*"]
8+
include_in_copy = ["repo-files/*", "assets/*"]
99
}
1010

1111
include "root" {

0 commit comments

Comments
 (0)