providers/app_gw: generate docker-compose in code

This commit is contained in:
Jens Langhammer 2020-07-26 22:01:37 +02:00
parent 83205f1b49
commit ddb0fdee98
4 changed files with 66 additions and 36 deletions

View File

@ -1,17 +1,13 @@
"""passbook app_gw models""" """passbook app_gw models"""
import string
from random import SystemRandom
from typing import Optional, Type from typing import Optional, Type
from django.core.validators import URLValidator from django.core.validators import URLValidator
from django.db import models from django.db import models
from django.forms import ModelForm from django.forms import ModelForm
from django.http import HttpRequest from django.http import HttpRequest
from django.shortcuts import reverse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from oidc_provider.models import Client from oidc_provider.models import Client
from passbook import __version__
from passbook.core.models import Provider from passbook.core.models import Provider
from passbook.lib.utils.template import render_to_string from passbook.lib.utils.template import render_to_string
@ -33,21 +29,12 @@ class ApplicationGatewayProvider(Provider):
def html_setup_urls(self, request: HttpRequest) -> Optional[str]: def html_setup_urls(self, request: HttpRequest) -> Optional[str]:
"""return template and context modal with URLs for authorize, token, openid-config, etc""" """return template and context modal with URLs for authorize, token, openid-config, etc"""
cookie_secret = "".join( from passbook.providers.app_gw.views import DockerComposeView
SystemRandom().choice(string.ascii_uppercase + string.digits)
for _ in range(50) docker_compose_yaml = DockerComposeView(request=request).get_compose(self)
)
full_issuer_user = request.build_absolute_uri(
reverse("passbook_providers_oidc:authorize")
)
return render_to_string( return render_to_string(
"app_gw/setup_modal.html", "app_gw/setup_modal.html",
{ {"provider": self, "docker_compose": docker_compose_yaml},
"provider": self,
"cookie_secret": cookie_secret,
"version": __version__,
"full_issuer_user": full_issuer_user,
},
) )
def __str__(self): def __str__(self):

View File

@ -1,14 +0,0 @@
version: "3.5"
services:
passbook_gatekeeper:
image: beryju/passbook-gatekeeper:{{ version }}
ports:
- 4180:4180
environment:
OAUTH2_PROXY_CLIENT_ID: {{ provider.client.client_id }}
OAUTH2_PROXY_CLIENT_SECRET: {{ provider.client.client_secret }}
OAUTH2_PROXY_REDIRECT_URL: https://{{ provider.external_host }}/oauth2/callback
OAUTH2_PROXY_OIDC_ISSUER_URL: {{ full_issuer_user }}
OAUTH2_PROXY_COOKIE_SECRET: {{ cookie_secret }}
OAUTH2_PROXY_UPSTREAMS: http://{{ provider.internal_host }}

View File

@ -26,7 +26,7 @@
</div> </div>
<div class="pf-c-modal-box__body"> <div class="pf-c-modal-box__body">
{% trans 'Add the following snippet to your docker-compose file.' %} {% trans 'Add the following snippet to your docker-compose file.' %}
<textarea class="codemirror" readonly data-cm-mode="yaml">{% include 'app_gw/docker-compose.yml' %}</textarea> <textarea class="codemirror" readonly data-cm-mode="yaml">{{ docker_compose }}</textarea>
</div> </div>
<footer class="pf-c-modal-box__footer pf-m-align-left"> <footer class="pf-c-modal-box__footer pf-m-align-left">
<button data-modal-close class="pf-c-button pf-m-primary" type="button">{% trans 'Close' %}</button> <button data-modal-close class="pf-c-button pf-m-primary" type="button">{% trans 'Close' %}</button>

View File

@ -1,33 +1,90 @@
"""passbook app_gw views""" """passbook app_gw views"""
import string import string
from random import SystemRandom from random import SystemRandom
from urllib.parse import urlparse
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Model
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render, reverse
from django.views import View from django.views import View
from guardian.shortcuts import get_objects_for_user
from structlog import get_logger from structlog import get_logger
from yaml import safe_dump
from passbook import __version__ from passbook import __version__
from passbook.core.models import User
from passbook.providers.app_gw.models import ApplicationGatewayProvider from passbook.providers.app_gw.models import ApplicationGatewayProvider
ORIGINAL_URL = "HTTP_X_ORIGINAL_URL" ORIGINAL_URL = "HTTP_X_ORIGINAL_URL"
LOGGER = get_logger() LOGGER = get_logger()
def get_object_for_user_or_404(user: User, perm: str, **filters) -> Model:
"""Wrapper that combines get_objects_for_user and get_object_or_404"""
return get_object_or_404(get_objects_for_user(user, perm), **filters)
def get_cookie_secret(): def get_cookie_secret():
"""Generate random 50-character string for cookie-secret""" """Generate random 32-character string for cookie-secret"""
return "".join( return "".join(
SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(32) SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(32)
) )
class DockerComposeView(LoginRequiredMixin, View):
"""Generate docker-compose yaml"""
def get_compose(self, provider: ApplicationGatewayProvider) -> str:
"""Generate docker-compose yaml, version 3.5"""
full_issuer_user = self.request.build_absolute_uri(
reverse("passbook_providers_oidc:authorize")
)
env = {
"OAUTH2_PROXY_CLIENT_ID": provider.client.client_id,
"OAUTH2_PROXY_CLIENT_SECRET": provider.client.client_secret,
"OAUTH2_PROXY_REDIRECT_URL": f"{provider.external_host}/oauth2/callback",
"OAUTH2_PROXY_OIDC_ISSUER_URL": full_issuer_user,
"OAUTH2_PROXY_COOKIE_SECRET": get_cookie_secret(),
"OAUTH2_PROXY_UPSTREAMS": provider.internal_host,
}
if urlparse(provider.external_host).scheme != "https":
env["OAUTH2_PROXY_COOKIE_SECURE"] = "false"
compose = {
"version": "3.5",
"services": {
"passbook_gatekeeper": {
"image": f"beryju/passbook-gatekeeper:{__version__}",
"ports": ["4180:4180"],
"environment": env,
}
},
}
return safe_dump(compose, default_flow_style=False)
def get(self, request: HttpRequest, provider_pk: int) -> HttpResponse:
"""Render docker-compose file"""
provider: ApplicationGatewayProvider = get_object_for_user_or_404(
request.user,
"passbook_providers_app_gw.view_applicationgatewayprovider",
pk=provider_pk,
)
response = HttpResponse()
response.content_type = "application/x-yaml"
response.content = self.get_compose(provider.pk)
return response
class K8sManifestView(LoginRequiredMixin, View): class K8sManifestView(LoginRequiredMixin, View):
"""Generate K8s Deployment and SVC for gatekeeper""" """Generate K8s Deployment and SVC for gatekeeper"""
def get(self, request: HttpRequest, provider: int) -> HttpResponse: def get(self, request: HttpRequest, provider_pk: int) -> HttpResponse:
"""Render deployment template""" """Render deployment template"""
provider = get_object_or_404(ApplicationGatewayProvider, pk=provider) provider: ApplicationGatewayProvider = get_object_for_user_or_404(
request.user,
"passbook_providers_app_gw.view_applicationgatewayprovider",
pk=provider_pk,
)
return render( return render(
request, request,
"app_gw/k8s-manifest.yaml", "app_gw/k8s-manifest.yaml",