From 8c6c1d7c88e3d72c1e436fc19bda76b1f5b2d59c Mon Sep 17 00:00:00 2001
From: Stavros Moiras <stavros.moiras@cern.ch>
Date: Tue, 16 Nov 2021 10:44:55 +0100
Subject: [PATCH] OIDC support for python-magnumclient

---
 magnumclient/common/utils.py    | 55 ++++++++++++++++++++++++++++++---
 magnumclient/osc/v1/clusters.py | 17 +++++++++-
 2 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/magnumclient/common/utils.py b/magnumclient/common/utils.py
index 4a8cfb1..544d998 100644
--- a/magnumclient/common/utils.py
+++ b/magnumclient/common/utils.py
@@ -160,11 +160,11 @@ def handle_json_from_file(json_arg):
 
 
 def config_cluster(cluster, cluster_template, cfg_dir, force=False,
-                   certs=None, use_keystone=False):
+                   certs=None, use_keystone=False, use_oidc=False, oidc_browser=False):
     """Return and write configuration for the given cluster."""
     if cluster_template.coe == 'kubernetes':
         return _config_cluster_kubernetes(cluster, cluster_template, cfg_dir,
-                                          force, certs, use_keystone)
+                                          force, certs, use_keystone, use_oidc, oidc_browser)
     elif (cluster_template.coe == 'swarm'
           or cluster_template.coe == 'swarm-mode'):
         return _config_cluster_swarm(cluster, cluster_template, cfg_dir,
@@ -172,7 +172,7 @@ def config_cluster(cluster, cluster_template, cfg_dir, force=False,
 
 
 def _config_cluster_kubernetes(cluster, cluster_template, cfg_dir,
-                               force=False, certs=None, use_keystone=False):
+                               force=False, certs=None, use_keystone=False, use_oidc=False, oidc_browser=False):
     """Return and write configuration for the given kubernetes cluster."""
     cfg_file = "%s/config" % cfg_dir
     if cluster_template.tls_disabled or certs is None:
@@ -193,7 +193,54 @@ def _config_cluster_kubernetes(cluster, cluster_template, cfg_dir,
                "- name: %(name)s'\n"
                % {'name': cluster.name, 'api_address': cluster.api_address})
     else:
-        if not use_keystone:
+        if use_oidc:
+
+            # If cluster has the 'oidc_client_id' set then there is a custom client id
+            clientid = cluster.labels.get('oidc_client_id')
+
+            if not clientid:
+                # If not, then everything is managed by magnum, thus we add "oidc" and the cluster uuid (convention)
+                clientid = "openstack-magnum-" + cluster.uuid
+
+            if oidc_browser:
+                # Browser will pop up automatically during authentication
+                granttype = "auto"
+            else:
+                # Users will have to follow a link and paste a token from their local browser
+                granttype = "authcode-keyboard"
+
+            cfg = ("apiVersion: v1\n"
+                   "clusters:\n"
+                   "- cluster:\n"
+                   "    certificate-authority-data: %(ca)s\n"
+                   "    server: %(api_address)s\n"
+                   "  name: %(name)s\n"
+                   "contexts:\n"
+                   "- context:\n"
+                   "    cluster: %(name)s\n"
+                   "    user: oidc-user\n"
+                   "  name: default\n"
+                   "current-context: default\n"
+                   "kind: Config\n"
+                   "preferences: {}\n"
+                   "users:\n"
+                   "- name: oidc-user\n"
+                   "  user:\n"
+                   "    exec:\n"
+                   "      apiVersion: client.authentication.k8s.io/v1beta1\n"
+                   "      args:\n"
+                   "      - get-token\n"
+                   "      - --oidc-issuer-url=https://auth.cern.ch/auth/realms/cern\n"
+                   "      - --oidc-client-id=%(client)s\n"
+                   "      - --grant-type=%(granttype)s\n"
+                   "      command: kubectl-oidc_login\n"
+                   "      env: null\n"
+                   % {'name': cluster.name,
+                      'client' : clientid,
+                      'granttype' : granttype,
+                      'api_address': cluster.api_address,
+                      'ca': base64.encode_as_text(certs['ca'])})
+        elif not use_keystone:
             cfg = ("apiVersion: v1\n"
                    "clusters:\n"
                    "- cluster:\n"
diff --git a/magnumclient/osc/v1/clusters.py b/magnumclient/osc/v1/clusters.py
index 3ab06e9..16e56db 100644
--- a/magnumclient/osc/v1/clusters.py
+++ b/magnumclient/osc/v1/clusters.py
@@ -376,6 +376,19 @@ class ConfigCluster(command.Command):
             dest='use_keystone',
             default=False,
             help=_('Use Keystone token in config files.'))
+        parser.add_argument(
+            '--use-oidc',
+            action='store_true',
+            dest='use_oidc',
+            default=False,
+            help=_('Use oidc cluster config.'))
+        parser.add_argument(
+            '--oidc-browser',
+            action='store_true',
+            dest='oidc_browser',
+            default=False,
+            help=_('Changes the default oidc authentication method from keyboard to browser'))
+
 
         return parser
 
@@ -425,7 +438,9 @@ class ConfigCluster(command.Command):
         print(magnum_utils.config_cluster(
             cluster, cluster_template, parsed_args.dir,
             force=parsed_args.force, certs=tls,
-            use_keystone=parsed_args.use_keystone))
+            use_keystone=parsed_args.use_keystone,
+            use_oidc=parsed_args.use_oidc,
+            oidc_browser=parsed_args.oidc_browser))
 
 
 class ResizeCluster(command.Command):
-- 
GitLab