Downloadable Kubernetes configuration file

Kubernetes can use OpenStack application credentials for authentication.
Generate a kubeconfig file and make it available to download along with the
openrc and clouds.yaml files.

blueprint kubernetes-config-gen

Change-Id: I298370e7abf4f0d480bd5199060f24bab6d6daaa
This commit is contained in:
Claudio Pisa 2019-05-29 12:04:16 +00:00 committed by Ivan Kolodyazhny
parent a7a04da657
commit f381f4dd3c
9 changed files with 149 additions and 7 deletions

View File

@ -7,7 +7,7 @@ Settings Reference
Introduction
============
Horizon's settings broadly fall into three categories:
Horizon's settings broadly fall into four categories:
* `General Settings`_: this includes visual settings like the modal backdrop
style, bug url and theme configuration, as well as settings that affect every
@ -21,6 +21,8 @@ Horizon's settings broadly fall into three categories:
should read the `Django settings documentation
<https://docs.djangoproject.com/en/dev/topics/settings/>`_ to see the other
options available to you.
* `Other Settings`_: settings which do not fall into any of the above
categories.
To modify your settings, you have two options:
@ -2521,3 +2523,51 @@ Default: Absolute paths for `horizon/locale`, `openstack_auth/locale` and
Django uses relative paths by default so it causes localization issues
depending on your runtime settings. To avoid this we recommend to use absolute
paths for directories with locales.
Other Settings
==============
KUBECONFIG_ENABLED
------------------
.. versionadded:: TBD
Default: ``False``
Kubernetes clusters can use Keystone as an external identity provider.
Horizon can generate a ``kubeconfig`` file from the application credentials
control panel which can be used for authenticating with a Kubernetes cluster.
This setting enables this behavior.
.. seealso::
`KUBECONFIG_KUBERNETES_URL`_ and `KUBECONFIG_CERTIFICATE_AUTHORITY_DATA`_
to provide parameters for the ``kubeconfig`` file.
KUBECONFIG_KUBERNETES_URL
-------------------------
.. versionadded:: TBD
Default: ``""``
A Kubernetes API endpoint URL to be included in the generated ``kubeconfig``
file.
.. seealso::
`KUBECONFIG_ENABLED`_ to enable the ``kubeconfig`` file generation.
KUBECONFIG_CERTIFICATE_AUTHORITY_DATA
-------------------------------------
.. versionadded:: TBD
Default: ``""``
Kubernetes API endpoint certificate authority data to be included in the
generated ``kubeconfig`` file.
.. seealso::
`KUBECONFIG_ENABLED`_ to enable the ``kubeconfig`` file generation.

View File

@ -15,6 +15,8 @@
import datetime
import logging
from django.conf import settings
from django.forms import widgets
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_variables
@ -49,6 +51,10 @@ class CreateApplicationCredentialForm(forms.SelfHandlingForm):
required=False)
unrestricted = forms.BooleanField(label=_("Unrestricted (dangerous)"),
required=False)
kubernetes_namespace = forms.CharField(max_length=255,
label=_("Kubernetes Namespace"),
initial="default",
required=False)
def __init__(self, request, *args, **kwargs):
self.next_view = kwargs.pop('next_view', None)
@ -58,6 +64,8 @@ class CreateApplicationCredentialForm(forms.SelfHandlingForm):
role_names = [role['name'] for role in role_list]
role_choices = ((name, name) for name in role_names)
self.fields['roles'].choices = role_choices
if not settings.KUBECONFIG_ENABLED:
self.fields['kubernetes_namespace'].widget = widgets.HiddenInput()
# We have to protect the entire "data" dict because it contains the
# secret string.
@ -98,6 +106,8 @@ class CreateApplicationCredentialForm(forms.SelfHandlingForm):
)
self.request.session['application_credential'] = \
new_app_cred.to_dict()
(self.request.session['application_credential']
['kubernetes_namespace']) = data['kubernetes_namespace']
request.method = 'GET'
return self.next_view.as_view()(request)
except exceptions.Conflict:

View File

@ -40,4 +40,12 @@
actions, check "unrestricted".
{% endblocktrans %}
</p>
<p>
{% if kubeconfig_enabled %}
{% blocktrans trimmed %}
You can optionally provide a Kubernetes Namespace. It will be included in the
kubeconfig file which can be downloaded from the next screen.
{% endblocktrans %}
{% endif %}
</p>
{% endblock %}

View File

@ -31,5 +31,11 @@
<span class="fa fa-download"></span>
{{ download_clouds_yaml_label }}
</a>
{% if download_kubeconfig_url %}
<a href="{{ download_kubeconfig_url }}" class="btn btn-default">
<span class="fa fa-download"></span>
{{ download_kubeconfig_label }}
</a>
{% endif %}
<a onClick="location.href='{{cancel_url}}'" href="{{ cancel_url }}" class="btn btn-default">{{ cancel_label }}</a>
{% endblock %}

View File

@ -0,0 +1,26 @@
apiVersion: v1
kind: Config
clusters:
- name: kubernetes
cluster:
server: {{ kubernetes_url }}
certificate-authority-data: {{ kubernetes_certificate_authority_data }}
contexts:
- name: kubernetes
context:
cluster: kubernetes
user: {{ user }}
namespace: {{ kubernetes_namespace }}
current-context: kubernetes
users:
- name: {{ user }}
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: bin/kubectl-keystone-auth
args:
- "--keystone-url={{ auth_url }}
- "--domain-name=none"
- "--user-name={{ user }}"
- "--application-credential-id={{ application_credential_id }}"
- "--application-credential-secret={{ application_credential_secret }}"

View File

@ -28,6 +28,8 @@ urlpatterns = [
views.CreateSuccessfulView.as_view(), name='success'),
url(r'^download_openrc/$',
views.download_rc_file, name='download_openrc'),
url(r'^download_kubeconfig/$',
views.download_kubeconfig_file, name='download_kubeconfig'),
url(r'^download_clouds_yaml/$',
views.download_clouds_yaml_file, name='download_clouds_yaml'),
]

View File

@ -86,6 +86,11 @@ class CreateView(forms.ModalFormView):
kwargs['next_view'] = CreateSuccessfulView
return kwargs
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
context['kubeconfig_enabled'] = settings.KUBECONFIG_ENABLED
return context
class CreateSuccessfulView(forms.ModalFormView):
template_name = 'identity/application_credentials/success.html'
@ -97,15 +102,20 @@ class CreateSuccessfulView(forms.ModalFormView):
cancel_label = _("Close")
download_openrc_label = _("Download openrc file")
download_clouds_yaml_label = _("Download clouds.yaml")
download_kubeconfig_label = _("Download kubeconfig file")
def get_context_data(self, **kwargs):
context = super(CreateSuccessfulView, self).get_context_data(**kwargs)
context['download_openrc_label'] = self.download_openrc_label
context['download_clouds_yaml_label'] = self.download_clouds_yaml_label
context['download_kubeconfig_label'] = self.download_kubeconfig_label
context['download_openrc_url'] = reverse(
'horizon:identity:application_credentials:download_openrc')
context['download_clouds_yaml_url'] = reverse(
'horizon:identity:application_credentials:download_clouds_yaml')
if settings.KUBECONFIG_ENABLED:
context['download_kubeconfig_url'] = reverse(
'horizon:identity:application_credentials:download_kubeconfig')
return context
def get_initial(self):
@ -125,12 +135,18 @@ def _get_context(request):
interface = 'public'
region = getattr(request.user, 'services_region', '')
app_cred = request.session['application_credential']
context = dict(auth_url=auth_url,
interface=interface,
region=region,
application_credential_id=app_cred['id'],
application_credential_name=app_cred['name'],
application_credential_secret=app_cred['secret'])
context = {
'auth_url': auth_url,
'interface': interface,
'region': region,
'user': request.user,
'application_credential_id': app_cred['id'],
'application_credential_name': app_cred['name'],
'application_credential_secret': app_cred['secret'],
'kubernetes_namespace': app_cred['kubernetes_namespace'],
'kubernetes_url': settings.KUBECONFIG_KUBERNETES_URL,
'kubernetes_certificate_authority_data':
settings.KUBECONFIG_CERTIFICATE_AUTHORITY_DATA}
return context
@ -166,6 +182,14 @@ def download_clouds_yaml_file(request):
return _render_attachment(filename, template, context, request)
def download_kubeconfig_file(request):
context = _get_context(request)
template = 'identity/application_credentials/kubeconfig.template'
filename = 'app-cred-%s-kubeconfig' % context['application_credential_name']
response = _render_attachment(filename, template, context, request)
return response
class DetailView(views.HorizonTemplateView):
template_name = 'identity/application_credentials/detail.html'
page_title = "{{ application_credential.name }}"

View File

@ -374,3 +374,11 @@ REST_API_REQUIRED_SETTINGS = [
# and are not encrypted on the browser. This is an experimental API and
# may be deprecated in the future without notice.
REST_API_ADDITIONAL_SETTINGS = []
# Kubernetes clusters can use Keystone as an external identity provider.
# Horizon can generate a 'kubeconfig' file from the application credentials
# control panel which can be used for authenticating with a Kubernetes cluster.
# These settings control the kubeconfig parameters.
KUBECONFIG_ENABLED = False
KUBECONFIG_KUBERNETES_URL = ""
KUBECONFIG_CERTIFICATE_AUTHORITY_DATA = ""

View File

@ -0,0 +1,8 @@
---
features:
- |
[`blueprint kubernetes-config-gen <https://blueprints.launchpad.net/horizon/+spec/kubernetes-config-gen>`_]
Horizon now supports the optional automatic generation of a Kubernetes
configuration file (kubeconfig) based on application credentials. Adds
a new download button for this purpose in the application credentials
creation dialog.