From 67a20f249e33ffbea326f2be825e085847c34331 Mon Sep 17 00:00:00 2001 From: Samuel Paccoud - DINUM Date: Mon, 19 Aug 2024 22:38:41 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(backend)=20add=20url=20to=20download?= =?UTF-8?q?=20media=20attachments=20with=20access=20rights?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We make use of nginx subrequests to block media file downloads while we check for access rights. The request is then proxied to the object storage engine and authorization is added via the "Authorization" header. This way the media urls are static and can be stored in the document's json content without compromising on security: access control is done on all requests based on the user cookie session. --- CHANGELOG.md | 4 + src/backend/core/api/utils.py | 33 +++ src/backend/core/api/viewsets.py | 56 ++++- .../test_api_documents_attachment_upload.py | 6 +- .../test_api_documents_retrieve_auth.py | 213 ++++++++++++++++++ src/helm/env.d/dev/values.impress.yaml.gotmpl | 14 ++ .../env.d/preprod/values.impress.yaml.gotmpl | 21 ++ .../production/values.impress.yaml.gotmpl | 21 ++ .../env.d/staging/values.impress.yaml.gotmpl | 21 ++ src/helm/impress/templates/ingress_media.yaml | 83 +++++++ src/helm/impress/templates/media_svc.yaml | 14 ++ src/helm/impress/values.yaml | 36 ++- 12 files changed, 514 insertions(+), 8 deletions(-) create mode 100644 src/backend/core/api/utils.py create mode 100644 src/backend/core/tests/documents/test_api_documents_retrieve_auth.py create mode 100644 src/helm/impress/templates/ingress_media.yaml create mode 100644 src/helm/impress/templates/media_svc.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index a98e65db4..76fa1e3a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ 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). +# Added + +- ✨Add image attachments with access control + ## [Unreleased] diff --git a/src/backend/core/api/utils.py b/src/backend/core/api/utils.py new file mode 100644 index 000000000..53d84f681 --- /dev/null +++ b/src/backend/core/api/utils.py @@ -0,0 +1,33 @@ +"""Util to generate S3 authorization headers for object storage access control""" + +from django.core.files.storage import default_storage + +import botocore + + +def generate_s3_authorization_headers(key): + """ + Generate authorization headers for an s3 object. + These headers can be used as an alternative to signed urls with many benefits: + - the urls of our files never expire and can be stored in our documents' content + - we don't leak authorized urls that could be shared (file access can only be done + with cookies) + - access control is truly realtime + - the object storage service does not need to be exposed on internet + """ + url = default_storage.unsigned_connection.meta.client.generate_presigned_url( + "get_object", + ExpiresIn=0, + Params={"Bucket": default_storage.bucket_name, "Key": key}, + ) + request = botocore.awsrequest.AWSRequest(method="get", url=url) + + s3_client = default_storage.connection.meta.client + # pylint: disable=protected-access + credentials = s3_client._request_signer._credentials # noqa: SLF001 + frozen_credentials = credentials.get_frozen_credentials() + region = s3_client.meta.region_name + auth = botocore.auth.S3SigV4Auth(frozen_credentials, "s3", region) + auth.add_auth(request) + + return request diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 9248c2701..6384fa239 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -1,7 +1,9 @@ """API endpoints""" import os +import re import uuid +from urllib.parse import urlparse from django.conf import settings from django.contrib.postgres.aggregates import ArrayAgg @@ -30,7 +32,17 @@ from core import models from core.utils import email_invitation -from . import permissions, serializers +from . import permissions, serializers, utils + +ATTACHMENTS_FOLDER = "attachments" +UUID_REGEX = ( + r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" +) +FILE_EXT_REGEX = r"\.[a-zA-Z]{3,4}" +MEDIA_URL_PATTERN = re.compile( + f"{settings.MEDIA_URL:s}({UUID_REGEX:s})/" + f"({ATTACHMENTS_FOLDER:s}/{UUID_REGEX:s}{FILE_EXT_REGEX:s})$" +) # pylint: disable=too-many-ancestors @@ -422,6 +434,48 @@ def attachment_upload(self, request, *args, **kwargs): {"file": f"{settings.MEDIA_URL:s}{key:s}"}, status=status.HTTP_201_CREATED ) + @decorators.action(detail=False, methods=["get"], url_path="retrieve-auth") + def retrieve_auth(self, request, *args, **kwargs): + """ + This view is used by an Nginx subrequest to control access to a document's + attachment file. + + The original url is passed by nginx in the "HTTP_X_ORIGINAL_URL" header. + See corresponding ingress configuration in Helm chart and read about the + nginx.ingress.kubernetes.io/auth-url annotation to understand how the Nginx ingress + is configured to do this. + + Based on the original url and the logged in user, we must decide if we authorize Nginx + to let this request go through (by returning a 200 code) or if we block it (by returning + a 403 error). Note that we return 403 errors without any further details for security + reasons. + + When we let the request go through, we compute authorization headers that will be added to + the request going through thanks to the nginx.ingress.kubernetes.io/auth-response-headers + annotation. The request will then be proxied to the object storage backend who will + respond with the file after checking the signature included in headers. + """ + original_url = urlparse(request.META.get("HTTP_X_ORIGINAL_URL")) + match = MEDIA_URL_PATTERN.search(original_url.path) + + try: + pk, attachment_key = match.groups() + except AttributeError as excpt: + raise exceptions.PermissionDenied() from excpt + + # Check permission + try: + document = models.Document.objects.get(pk=pk) + except models.Document.DoesNotExist as excpt: + raise exceptions.PermissionDenied() from excpt + + if not document.get_abilities(request.user).get("retrieve", False): + raise exceptions.PermissionDenied() + + # Generate authorization headers and return an authorization to proceed with the request + request = utils.generate_s3_authorization_headers(f"{pk:s}/{attachment_key:s}") + return drf_response.Response("authorized", headers=request.headers, status=200) + class DocumentAccessViewSet( ResourceAccessViewsetMixin, diff --git a/src/backend/core/tests/documents/test_api_documents_attachment_upload.py b/src/backend/core/tests/documents/test_api_documents_attachment_upload.py index b2bb9200a..3f1282d31 100644 --- a/src/backend/core/tests/documents/test_api_documents_attachment_upload.py +++ b/src/backend/core/tests/documents/test_api_documents_attachment_upload.py @@ -103,9 +103,7 @@ def test_api_documents_attachment_upload_reader(via, mock_user_get_teams): @pytest.mark.parametrize("role", ["editor", "administrator", "owner"]) @pytest.mark.parametrize("via", VIA) -def test_api_documents_attachment_upload_success( - via, role, mock_user_get_teams, settings -): +def test_api_documents_attachment_upload_success(via, role, mock_user_get_teams): """ Editors, administrators and owners of a document should be able to upload an attachment. """ @@ -130,7 +128,7 @@ def test_api_documents_attachment_upload_success( assert response.status_code == 201 - pattern = re.compile(rf"^{settings.MEDIA_URL}{document.id!s}/attachments/(.*)\.jpg") + pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.jpg") match = pattern.search(response.json()["file"]) file_id = match.group(1) diff --git a/src/backend/core/tests/documents/test_api_documents_retrieve_auth.py b/src/backend/core/tests/documents/test_api_documents_retrieve_auth.py new file mode 100644 index 000000000..4724fc214 --- /dev/null +++ b/src/backend/core/tests/documents/test_api_documents_retrieve_auth.py @@ -0,0 +1,213 @@ +""" +Test file uploads API endpoint for users in impress's core app. +""" + +import uuid +from io import BytesIO +from urllib.parse import urlparse + +from django.conf import settings +from django.core.files.storage import default_storage +from django.utils import timezone + +import pytest +import requests +from rest_framework.test import APIClient + +from core import factories +from core.tests.conftest import TEAM, USER, VIA + +pytestmark = pytest.mark.django_db + + +def test_api_documents_retrieve_auth_anonymous_public(): + """Anonymous users should be able to retrieve attachments linked to a public document""" + document = factories.DocumentFactory(is_public=True) + + filename = f"{uuid.uuid4()!s}.jpg" + key = f"{document.pk!s}/attachments/{filename:s}" + + default_storage.connection.meta.client.put_object( + Bucket=default_storage.bucket_name, + Key=key, + Body=BytesIO(b"my prose"), + ContentType="text/plain", + ) + + original_url = f"http://localhost/media/{key:s}" + response = APIClient().get( + "/api/v1.0/documents/retrieve-auth/", HTTP_X_ORIGINAL_URL=original_url + ) + + assert response.status_code == 200 + + authorization = response["Authorization"] + assert "AWS4-HMAC-SHA256 Credential=" in authorization + assert ( + "SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=" + in authorization + ) + assert response["X-Amz-Date"] == timezone.now().strftime("%Y%m%dT%H%M%SZ") + + s3_url = urlparse(settings.AWS_S3_ENDPOINT_URL) + file_url = f"{settings.AWS_S3_ENDPOINT_URL:s}/impress-media-storage/{key:s}" + response = requests.get( + file_url, + headers={ + "authorization": authorization, + "x-amz-date": response["x-amz-date"], + "x-amz-content-sha256": response["x-amz-content-sha256"], + "Host": f"{s3_url.hostname:s}:{s3_url.port:d}", + }, + timeout=1, + ) + assert response.content.decode("utf-8") == "my prose" + + +def test_api_documents_retrieve_auth_anonymous_not_public(): + """ + Anonymous users should not be allowed to retrieve attachments linked to a document + that is not public. + """ + document = factories.DocumentFactory(is_public=False) + + filename = f"{uuid.uuid4()!s}.jpg" + media_url = f"http://localhost/media/{document.pk!s}/attachments/{filename:s}" + + response = APIClient().get( + "/api/v1.0/documents/retrieve-auth/", HTTP_X_ORIGINAL_URL=media_url + ) + + assert response.status_code == 403 + assert "Authorization" not in response + + +def test_api_documents_retrieve_auth_authenticated_public(): + """ + Authenticated users who are not related to a document should be able to + retrieve attachments linked to a public document. + """ + document = factories.DocumentFactory(is_public=True) + + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + filename = f"{uuid.uuid4()!s}.jpg" + key = f"{document.pk!s}/attachments/{filename:s}" + + default_storage.connection.meta.client.put_object( + Bucket=default_storage.bucket_name, + Key=key, + Body=BytesIO(b"my prose"), + ContentType="text/plain", + ) + + original_url = f"http://localhost/media/{key:s}" + response = APIClient().get( + "/api/v1.0/documents/retrieve-auth/", HTTP_X_ORIGINAL_URL=original_url + ) + + assert response.status_code == 200 + + authorization = response["Authorization"] + assert "AWS4-HMAC-SHA256 Credential=" in authorization + assert ( + "SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=" + in authorization + ) + assert response["X-Amz-Date"] == timezone.now().strftime("%Y%m%dT%H%M%SZ") + + s3_url = urlparse(settings.AWS_S3_ENDPOINT_URL) + file_url = f"{settings.AWS_S3_ENDPOINT_URL:s}/impress-media-storage/{key:s}" + response = requests.get( + file_url, + headers={ + "authorization": authorization, + "x-amz-date": response["x-amz-date"], + "x-amz-content-sha256": response["x-amz-content-sha256"], + "Host": f"{s3_url.hostname:s}:{s3_url.port:d}", + }, + timeout=1, + ) + assert response.content.decode("utf-8") == "my prose" + + +def test_api_documents_retrieve_auth_authenticated_not_public(): + """ + Authenticated users who are not related to a document should not be allowed to + retrieve attachments linked to a document that is not public. + """ + document = factories.DocumentFactory(is_public=False) + + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + filename = f"{uuid.uuid4()!s}.jpg" + media_url = f"http://localhost/media/{document.pk!s}/attachments/{filename:s}" + + response = APIClient().get( + "/api/v1.0/documents/retrieve-auth/", HTTP_X_ORIGINAL_URL=media_url + ) + + assert response.status_code == 403 + assert "Authorization" not in response + + +@pytest.mark.parametrize("is_public", [True, False]) +@pytest.mark.parametrize("via", VIA) +def test_api_documents_retrieve_auth_related(via, is_public, mock_user_get_teams): + """ + Users who have a role on a document, whatever the role, should be able to + retrieve related attachments. + """ + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + document = factories.DocumentFactory(is_public=is_public) + if via == USER: + factories.UserDocumentAccessFactory(document=document, user=user) + elif via == TEAM: + mock_user_get_teams.return_value = ["lasuite", "unknown"] + factories.TeamDocumentAccessFactory(document=document, team="lasuite") + + filename = f"{uuid.uuid4()!s}.jpg" + key = f"{document.pk!s}/attachments/{filename:s}" + + default_storage.connection.meta.client.put_object( + Bucket=default_storage.bucket_name, + Key=key, + Body=BytesIO(b"my prose"), + ContentType="text/plain", + ) + + original_url = f"http://localhost/media/{key:s}" + response = client.get( + "/api/v1.0/documents/retrieve-auth/", HTTP_X_ORIGINAL_URL=original_url + ) + + assert response.status_code == 200 + + authorization = response["Authorization"] + assert "AWS4-HMAC-SHA256 Credential=" in authorization + assert ( + "SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=" + in authorization + ) + assert response["X-Amz-Date"] == timezone.now().strftime("%Y%m%dT%H%M%SZ") + + s3_url = urlparse(settings.AWS_S3_ENDPOINT_URL) + file_url = f"{settings.AWS_S3_ENDPOINT_URL:s}/impress-media-storage/{key:s}" + response = requests.get( + file_url, + headers={ + "authorization": authorization, + "x-amz-date": response["x-amz-date"], + "x-amz-content-sha256": response["x-amz-content-sha256"], + "Host": f"{s3_url.hostname:s}:{s3_url.port:d}", + }, + timeout=1, + ) + assert response.content.decode("utf-8") == "my prose" diff --git a/src/helm/env.d/dev/values.impress.yaml.gotmpl b/src/helm/env.d/dev/values.impress.yaml.gotmpl index 8f8768b84..a2cf6d967 100644 --- a/src/helm/env.d/dev/values.impress.yaml.gotmpl +++ b/src/helm/env.d/dev/values.impress.yaml.gotmpl @@ -103,3 +103,17 @@ ingressWS: ingressAdmin: enabled: true host: impress.127.0.0.1.nip.io + +ingressMedia: + enabled: true + host: impress.127.0.0.1.nip.io + + annotations: + nginx.ingress.kubernetes.io/auth-url: https://impress.127.0.0.1.nip.io/api/v1.0/documents/retrieve-auth/ + nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256" + nginx.ingress.kubernetes.io/upstream-vhost: minio.impress.svc.cluster.local:9000 + nginx.ingress.kubernetes.io/rewrite-target: /impress-media-storage/$1 + +serviceMedia: + host: minio.impress.svc.cluster.local + port: 9000 diff --git a/src/helm/env.d/preprod/values.impress.yaml.gotmpl b/src/helm/env.d/preprod/values.impress.yaml.gotmpl index 66513dd9d..15502d324 100644 --- a/src/helm/env.d/preprod/values.impress.yaml.gotmpl +++ b/src/helm/env.d/preprod/values.impress.yaml.gotmpl @@ -154,3 +154,24 @@ ingressAdmin: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/start nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/auth + +ingressMedia: + enabled: true + host: impress-preprod.beta.numerique.gouv.fr + + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/auth-url: https://impress-preprod.beta.numerique.gouv.fr/api/v1.0/documents/retrieve-auth/ + nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256" + nginx.ingress.kubernetes.io/upstream-vhost: + secretKeyRef: + name: impress-media-storage.bucket.libre.sh + key: url + nginx.ingress.kubernetes.io/rewrite-target: /impress-media-storage/$1 + +serviceMedia: + host: + secretKeyRef: + name: impress-media-storage.bucket.libre.sh + key: url + port: 9000 diff --git a/src/helm/env.d/production/values.impress.yaml.gotmpl b/src/helm/env.d/production/values.impress.yaml.gotmpl index 3447c04fb..94fafd93d 100644 --- a/src/helm/env.d/production/values.impress.yaml.gotmpl +++ b/src/helm/env.d/production/values.impress.yaml.gotmpl @@ -154,3 +154,24 @@ ingressAdmin: cert-manager.io/cluster-issuer: letsencrypt nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/start nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/auth + +ingressMedia: + enabled: true + host: docs.numerique.gouv.fr + + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/auth-url: https://docs.numerique.gouv.fr/api/v1.0/documents/retrieve-auth/ + nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256" + nginx.ingress.kubernetes.io/upstream-vhost: + secretKeyRef: + name: impress-media-storage.bucket.libre.sh + key: url + nginx.ingress.kubernetes.io/rewrite-target: /impress-media-storage/$1 + +serviceMedia: + host: + secretKeyRef: + name: impress-media-storage.bucket.libre.sh + key: url + port: 9000 diff --git a/src/helm/env.d/staging/values.impress.yaml.gotmpl b/src/helm/env.d/staging/values.impress.yaml.gotmpl index ae8b2a8db..be1925dcd 100644 --- a/src/helm/env.d/staging/values.impress.yaml.gotmpl +++ b/src/helm/env.d/staging/values.impress.yaml.gotmpl @@ -154,3 +154,24 @@ ingressAdmin: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/start nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy-preprod.beta.numerique.gouv.fr/oauth2/auth + +ingressMedia: + enabled: true + host: impress-staging.beta.numerique.gouv.fr + + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/auth-url: https://impress-staging.beta.numerique.gouv.fr/api/v1.0/documents/retrieve-auth/ + nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256" + nginx.ingress.kubernetes.io/upstream-vhost: + secretKeyRef: + name: impress-media-storage.bucket.libre.sh + key: url + nginx.ingress.kubernetes.io/rewrite-target: /impress-media-storage/$1 + +serviceMedia: + host: + secretKeyRef: + name: impress-media-storage.bucket.libre.sh + key: url + port: 9000 diff --git a/src/helm/impress/templates/ingress_media.yaml b/src/helm/impress/templates/ingress_media.yaml new file mode 100644 index 000000000..331753a88 --- /dev/null +++ b/src/helm/impress/templates/ingress_media.yaml @@ -0,0 +1,83 @@ +{{- if .Values.ingressMedia.enabled -}} +{{- $fullName := include "impress.fullname" . -}} +{{- if and .Values.ingressMedia.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingressMedia.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingressMedia.annotations "kubernetes.io/ingress.class" .Values.ingressMedia.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-media + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "impress.labels" . | nindent 4 }} + {{- with .Values.ingressMedia.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingressMedia.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingressMedia.className }} + {{- end }} + {{- if .Values.ingressMedia.tls.enabled }} + tls: + {{- if .Values.ingressMedia.host }} + - secretName: {{ $fullName }}-tls + hosts: + - {{ .Values.ingressMedia.host | quote }} + {{- end }} + {{- range .Values.ingressMedia.tls.additional }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.ingressMedia.host }} + - host: {{ .Values.ingressMedia.host | quote }} + http: + paths: + - path: {{ .Values.ingressMedia.path | quote }} + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }}-media + port: + number: {{ .Values.serviceMedia.port }} + {{- else }} + serviceName: {{ $fullName }}-media + servicePort: {{ .Values.serviceMedia.port }} + {{- end }} + {{- end }} + {{- range .Values.ingressMedia.hosts }} + - host: {{ . | quote }} + http: + paths: + - path: {{ $.Values.ingressMedia.path | quote }} + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }}-media + port: + number: {{ .Values.serviceMedia.port }} + {{- else }} + serviceName: {{ $fullName }}-media + servicePort: {{ .Values.serviceMedia.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/src/helm/impress/templates/media_svc.yaml b/src/helm/impress/templates/media_svc.yaml new file mode 100644 index 000000000..dc7bf0353 --- /dev/null +++ b/src/helm/impress/templates/media_svc.yaml @@ -0,0 +1,14 @@ +{{- $fullName := include "impress.fullname" . -}} +{{- $component := "media" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ $fullName }}-media + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "impress.common.labels" (list . $component) | nindent 4 }} + annotations: + {{- toYaml $.Values.serviceMedia.annotations | nindent 4 }} +spec: + type: ExternalName + externalName: {{ $.Values.serviceMedia.host }} diff --git a/src/helm/impress/values.yaml b/src/helm/impress/values.yaml index 60dbbcce7..635c1d84e 100644 --- a/src/helm/impress/values.yaml +++ b/src/helm/impress/values.yaml @@ -37,7 +37,7 @@ ingress: ## @param ingress.hosts Additional host to configure for the Ingress hosts: [] # - chart-example.local - ## @param ingress.tls.enabled Weather to enable TLS for the Ingress + ## @param ingress.tls.enabled Wether to enable TLS for the Ingress ## @skip ingress.tls.additional ## @extra ingress.tls.additional[].secretName Secret name for additional TLS config ## @extra ingress.tls.additional[].hosts[] Hosts for additional TLS config @@ -60,7 +60,7 @@ ingressWS: ## @param ingress.hosts Additional host to configure for the Ingress hosts: [] # - chart-example.local - ## @param ingressWS.tls.enabled Weather to enable TLS for the Ingress + ## @param ingressWS.tls.enabled Wether to enable TLS for the Ingress ## @skip ingressWS.tls.additional ## @extra ingressWS.tls.additional[].secretName Secret name for additional TLS config ## @extra ingressWS.tls.additional[].hosts[] Hosts for additional TLS config @@ -87,7 +87,7 @@ ingressAdmin: ## @param ingressAdmin.hosts Additional host to configure for the Ingress hosts: [ ] # - chart-example.local - ## @param ingressAdmin.tls.enabled Weather to enable TLS for the Ingress + ## @param ingressAdmin.tls.enabled Wether to enable TLS for the Ingress ## @skip ingressAdmin.tls.additional ## @extra ingressAdmin.tls.additional[].secretName Secret name for additional TLS config ## @extra ingressAdmin.tls.additional[].hosts[] Hosts for additional TLS config @@ -95,6 +95,36 @@ ingressAdmin: enabled: true additional: [] +## @param ingressMedia.enabled whether to enable the Ingress or not +## @param ingressMedia.className IngressClass to use for the Ingress +## @param ingressMedia.host Host for the Ingress +## @param ingressMedia.path Path to use for the Ingress +ingressMedia: + enabled: false + className: null + host: impress.example.com + path: /media/(.*) + ## @param ingressMedia.hosts Additional host to configure for the Ingress + hosts: [ ] + # - chart-example.local + ## @param ingressMedia.tls.enabled Wether to enable TLS for the Ingress + ## @skip ingressMedia.tls.additional + ## @extra ingressMedia.tls.additional[].secretName Secret name for additional TLS config + ## @extra ingressMedia.tls.additional[].hosts[] Hosts for additional TLS config + tls: + enabled: true + additional: [] + + annotations: + nginx.ingress.kubernetes.io/auth-url: https://impress.example.com/api/v1.0/documents/retrieve-auth/ + nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256" + nginx.ingress.kubernetes.io/upstream-vhost: minio.impress.svc.cluster.local:9000 + +serviceMedia: + host: minio.impress.svc.cluster.local + port: 9000 + annotations: {} + ## @section backend