summaryrefslogtreecommitdiffstats
path: root/custodia/kubernetes/authz.py
blob: cb9c68dfaaf25f4f44cdbc072a06d853ef494219 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Copyright (C) 2015  Custodia Project Contributors - see LICENSE file

import requests

from custodia import log
from custodia.httpd.authorizers import HTTPAuthorizer

DEFAULT_API_SERVER = 'http://localhost:8080'


class KubeAuthz(HTTPAuthorizer):

    def __init__(self, config=None):
        super(KubeAuthz, self).__init__(config)
        self.path = self.config.get('path', '/nodes')
        self.secrets = self.config.get('secrets', '/secrets')
        self.label = self.config.get('secrets_label', 'secrets_namespace')
        self.server_api = self.config.get('kube_api_server',
                                          DEFAULT_API_SERVER)

    def handle(self, request):
        reqpath = path = request.get('path', '')
        prefix = path

        while prefix.startswith('/'):
            if prefix == self.path:
                break
            else:
                prefix, _ = prefix.rsplit('/', 1)

        if prefix != self.path:
            self.logger.debug("Prefix %s does not match path %s",
                              prefix, reqpath)
            return None

        trail = path[len(prefix) + 1:]

        (namespace, podname, secret) = trail.split('/', 2)
        self.logger.debug("Checking if pod %s/%s has access to secret %s",
                          namespace, podname, secret)

        try:
            r = requests.get('%s/api/v1/namespaces/%s/pods/%s' % (
                             self.server_api, namespace, podname))
            r.raise_for_status()
            data = r.json()
            node_id = data["spec"]["nodeName"]
            secrets_namespace = data["metadata"]["labels"][self.label]
        except Exception:  # pylint: disable=broad-except
            self.logger.exception("Failed to fecth data from Kube API Server")
            self.audit_svc_access(log.AUDIT_SVC_AUTHZ_FAIL,
                                  request['client_id'], path)
            return False

        self.logger.debug(
            "Pod %s/%s runs on node %s with secret namespace %s.",
            namespace, podname, node_id, secrets_namespace)

        if node_id != request.get("remote_user"):
            self.logger.debug("Node authenticated as %s, but pod is believed "
                              "to be running on %s",
                              request.get("remote_user"), node_id)
            self.audit_svc_access(log.AUDIT_SVC_AUTHZ_FAIL,
                                  request['client_id'], path)
            return False

        request['path'] = '/'.join([self.secrets, secrets_namespace, secret])
        self.audit_svc_access(log.AUDIT_SVC_AUTHZ_PASS, request['client_id'],
                              "%s -> %s" % (path, request['path']))
        return True