Skip to content

Commit

Permalink
Pass project's oidc client secret through context (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
nuwang committed Jul 15, 2020
1 parent 054a652 commit 75cfd31
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
18 changes: 18 additions & 0 deletions cloudman/clusterman/clients/kube_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(self):
super(KubeClient, self).__init__(self)
self._namespace_svc = KubeNamespaceService(self)
self._node_svc = KubeNodeService(self)
self._secret_svc = KubeSecretService(self)

@staticmethod
def _check_environment():
Expand All @@ -36,6 +37,10 @@ def namespaces(self):
def nodes(self):
return self._node_svc

@property
def secrets(self):
return self._secret_svc


class KubeNamespaceService(KubeService):

Expand Down Expand Up @@ -111,3 +116,16 @@ def drain(self, node, force=True, timeout=120, ignore_daemonsets=True):
f"--force={'true' if force else 'false'}",
f"--ignore-daemonsets={'true' if ignore_daemonsets else 'false'}"]
)


class KubeSecretService(KubeService):

def __init__(self, client):
super(KubeSecretService, self).__init__(client)

def get(self, secret_name, namespace=None):
command = ["kubectl", "get", "secrets", "-o", "yaml", secret_name]
if namespace:
command += ["-n", namespace]
data = helpers.run_yaml_command(command)
return data
45 changes: 44 additions & 1 deletion cloudman/clusterman/tests/mock_kubectl.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import copy
import csv
import yaml

Expand Down Expand Up @@ -100,6 +101,24 @@ def __init__(self):
}
}
]
self.secrets = [
{
'apiVersion': 'v1',
'data': {'POSTGRES_DATABASE': 'cm9vdA==',
'POSTGRES_HOST': 'a2V5Y2xvYWstcG9zdGdyZXNxbA==',
'POSTGRES_SUPERUSER': 'dHJ1ZQ==',
'oidc-client-secret': 'ZXhhbXBsZS1rZXljbG9hay1DTmY3eVhwY1M3UXZLM0JLZ0plejBTbV9xYTBXRG1aRnpFSzlhcXRmdlZJPQ=='},
'kind': 'Secret',
'metadata': {'creationTimestamp': '2020-07-10T15:55:57Z',
'labels': {'app': 'keycloak'},
'name': 'gvl-projman-secret',
'namespace': 'default',
'resourceVersion': '4664946',
'selfLink': '/api/v1/namespaces/default/secrets/keycloak-db-secret',
'uid': '48ae55dc-2bed-4bee-9720-28ae725e47f0'},
'type': 'Opaque'
}
]
self.parser = self._create_parser()

def _create_parser(self):
Expand Down Expand Up @@ -129,14 +148,21 @@ def _create_parser(self):
'--field-selector', type=str)
parser_list_pods.add_argument('-o', choices=['yaml'], default="yaml")
parser_list_pods.set_defaults(func=self._kubectl_get_pods)
# kubectl get secrets
parser_list_secrets = subparsers_get.add_parser(
'secrets', help='List secrets')
parser_list_secrets.add_argument('-o', choices=['yaml'], default="yaml")
parser_list_secrets.add_argument('-n', "--namespace", default=None)
parser_list_secrets.add_argument('name', default=None)
parser_list_secrets.set_defaults(func=self._kubectl_get_secrets)

# kubectl create
parser_create = subparsers.add_parser('create', help='create')
subparsers_create = parser_create.add_subparsers(
help='Resources to create')
# kubectl create namespace
parser_create_ns = subparsers_create.add_parser('namespace',
help='create a namespace')
help='create a namespace')
parser_create_ns.add_argument(
'namespace', type=str, help='namespace name')
parser_create_ns.set_defaults(func=self._kubectl_create_namespace)
Expand Down Expand Up @@ -247,3 +273,20 @@ def _kubectl_drain(self, args):
with StringIO() as output:
output.write(f"node/{args.node_name} drained")
return output.getvalue()

def _kubectl_get_secrets(self, args):
if args.name:
# Temporary workaround to always return a matching secret to the
# name requested. This is because the secret should have been auto created
# when the projman helm chart is installed, which we aren't doing in the mocker.
secret = copy.deepcopy(self.secrets[0])
secret.get('metadata')['name'] = args.name
response = secret
else:
# get a copy of the response template
response = dict(self.list_template)
# add node to template
response['items'] = self.secrets
with StringIO() as output:
yaml.dump(response, stream=output, default_flow_style=False)
return output.getvalue()
13 changes: 13 additions & 0 deletions cloudman/projman/api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
"""ProjMan Service API."""
import base64

from django.contrib.auth.models import User
from django.template.defaultfilters import slugify

from . import models
from clusterman.clients.kube_client import KubeClient
from helmsman.api import HelmsManAPI, HMServiceContext
from helmsman.api import NamespaceExistsException
from rest_framework.exceptions import PermissionDenied
Expand Down Expand Up @@ -187,6 +190,14 @@ def get(self, chart_id):
return (self._to_proj_chart(chart)
if chart and chart.namespace == self.project.namespace else None)

def _get_project_oidc_secret(self):
try:
secret = KubeClient().secrets.get(f"{self.project.namespace}-projman-secrets",
namespace=self.project.namespace)
return base64.b64decode(secret.get('data').get('oidc-client-secret')).decode('utf-8')
except Exception:
return None

def create(self, template_name, release_name=None,
values=None, context=None):
self.check_permissions('projman.add_chart')
Expand All @@ -197,6 +208,8 @@ def create(self, template_name, release_name=None,
'name': self.project.name,
'namespace': self.project.namespace,
'access_path': f"/{self.project.namespace}",
'oidc_client_id': f"projman-{self.project.namespace}",
'oidc_client_secret': self._get_project_oidc_secret()
}})
return self._to_proj_chart(
template.install(self.project.namespace, release_name,
Expand Down

0 comments on commit 75cfd31

Please sign in to comment.