Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Securing the cluster created by Juju #47835

Merged
merged 2 commits into from
Jun 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ server {
proxy_set_header Connection $http_connection;
proxy_set_header X-Stream-Protocol-Version $http_x_stream_protocol_version;

proxy_ssl_certificate {{ server_certificate }};
proxy_ssl_certificate_key {{ server_key }};

add_header X-Stream-Protocol-Version $upstream_http_x_stream_protocol_version;

proxy_pass https://target_service;
Expand Down
3 changes: 2 additions & 1 deletion cluster/juju/layers/kubernetes-e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ and then relate the `kubernetes-e2e` charm.
```shell
juju deploy kubernetes-core
juju deploy cs:~containers/kubernetes-e2e
juju add-relation kubernetes-e2e kubernetes-master
juju add-relation kubernetes-e2e:kube-control kubernetes-master:kube-control
juju add-relation kubernetes-e2e:kubernetes-master kubernetes-master:kube-api-endpoint
juju add-relation kubernetes-e2e easyrsa
```

Expand Down
1 change: 1 addition & 0 deletions cluster/juju/layers/kubernetes-e2e/layer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ includes:
- layer:tls-client
- layer:snap
- interface:http
- interface:kube-control
options:
tls-client:
ca_certificate_path: '/srv/kubernetes/ca.crt'
Expand Down
3 changes: 3 additions & 0 deletions cluster/juju/layers/kubernetes-e2e/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ series:
requires:
kubernetes-master:
interface: http
kube-control:
interface: kube-control
resources:
kubectl:
type: file
Expand All @@ -23,3 +25,4 @@ resources:
type: file
filename: kubernetes-test.snap
description: kubernetes-test snap

68 changes: 53 additions & 15 deletions cluster/juju/layers/kubernetes-e2e/reactive/kubernetes_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,22 @@ def reset_delivery_states():


@when('kubernetes-e2e.installed')
def report_status():
''' Report the status of the charm. '''
messaging()


def messaging():
''' Probe our relations to determine the propper messaging to the
end user '''

missing_services = []
if not is_state('kubernetes-master.available'):
missing_services.append('kubernetes-master')
missing_services.append('kubernetes-master:http')
if not is_state('certificates.available'):
missing_services.append('certificates')
if not is_state('kubeconfig.ready'):
missing_services.append('kubernetes-master:kube-control')

if missing_services:
if len(missing_services) > 1:
Expand Down Expand Up @@ -80,34 +87,44 @@ def install_snaps():

@when('tls_client.ca.saved', 'tls_client.client.certificate.saved',
'tls_client.client.key.saved', 'kubernetes-master.available',
'kubernetes-e2e.installed')
'kubernetes-e2e.installed', 'kube-control.auth.available')
@when_not('kubeconfig.ready')
def prepare_kubeconfig_certificates(master):
def prepare_kubeconfig_certificates(master, kube_control):
''' Prepare the data to feed to create the kubeconfig file. '''

layer_options = layer.options('tls-client')
# Get all the paths to the tls information required for kubeconfig.
ca = layer_options.get('ca_certificate_path')
key = layer_options.get('client_key_path')
cert = layer_options.get('client_certificate_path')
creds = kube_control.get_auth_credentials()

servers = get_kube_api_servers(master)

# pedantry
kubeconfig_path = '/home/ubuntu/.kube/config'

# Create kubernetes configuration in the default location for ubuntu.
create_kubeconfig('/root/.kube/config', servers[0], ca, key, cert,
user='root')
create_kubeconfig(kubeconfig_path, servers[0], ca, key, cert,
user='ubuntu')
create_kubeconfig('/root/.kube/config', servers[0], ca,
token=creds['client_token'], user='root')
create_kubeconfig(kubeconfig_path, servers[0], ca,
token=creds['client_token'], user='ubuntu')
# Set permissions on the ubuntu users kubeconfig to ensure a consistent UX
cmd = ['chown', 'ubuntu:ubuntu', kubeconfig_path]
check_call(cmd)

messaging()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dont do this. You're making an explicit invocation of a method that is controlled by a decorator.

What I suggest is to move the messaging method into a non-decorated space in the source file, and write a new method declaration for invoking the messaging() method during the @when('kubernetes.e2e.installed') state is present, and you can then do this messaging() invocation inline like you have it (for guarantee of it being invoked when you expect it to be).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

set_state('kubeconfig.ready')


@when('kube-control.connected')
def request_credentials(kube_control):
""" Request authorization creds."""

# The kube-cotrol interface is created to support RBAC.
# At this point we might as well do the right thing and return the hostname
# even if it will only be used when we enable RBAC
user = 'system:masters'
kube_control.set_auth_request(user)


@when('kubernetes-e2e.installed', 'kubeconfig.ready')
def set_app_version():
''' Declare the application version to juju '''
Expand All @@ -124,19 +141,40 @@ def set_app_version():
hookenv.application_version_set(version_from.rstrip())


def create_kubeconfig(kubeconfig, server, ca, key, certificate, user='ubuntu',
context='juju-context', cluster='juju-cluster'):
def create_kubeconfig(kubeconfig, server, ca, key=None, certificate=None,
user='ubuntu', context='juju-context',
cluster='juju-cluster', password=None, token=None):
'''Create a configuration for Kubernetes based on path using the supplied
arguments for values of the Kubernetes server, CA, key, certificate, user
context and cluster.'''
if not key and not certificate and not password and not token:
raise ValueError('Missing authentication mechanism.')

# token and password are mutually exclusive. Error early if both are
# present. The developer has requested an impossible situation.
# see: kubectl config set-credentials --help
if token and password:
raise ValueError('Token and Password are mutually exclusive.')
# Create the config file with the address of the master server.
cmd = 'kubectl config --kubeconfig={0} set-cluster {1} ' \
'--server={2} --certificate-authority={3} --embed-certs=true'
check_call(split(cmd.format(kubeconfig, cluster, server, ca)))
# Delete old users
cmd = 'kubectl config --kubeconfig={0} unset users'
check_call(split(cmd.format(kubeconfig)))
# Create the credentials using the client flags.
cmd = 'kubectl config --kubeconfig={0} set-credentials {1} ' \
'--client-key={2} --client-certificate={3} --embed-certs=true'
check_call(split(cmd.format(kubeconfig, user, key, certificate)))
cmd = 'kubectl config --kubeconfig={0} ' \
'set-credentials {1} '.format(kubeconfig, user)

if key and certificate:
cmd = '{0} --client-key={1} --client-certificate={2} '\
'--embed-certs=true'.format(cmd, key, certificate)
if password:
cmd = "{0} --username={1} --password={2}".format(cmd, user, password)
# This is mutually exclusive from password. They will not work together.
if token:
cmd = "{0} --token={1}".format(cmd, token)
check_call(split(cmd))
# Create a default context with the cluster.
cmd = 'kubectl config --kubeconfig={0} set-context {1} ' \
'--cluster={2} --user={3}'
Expand Down
5 changes: 5 additions & 0 deletions cluster/juju/layers/kubernetes-master/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ options:
default: "stable"
description: |
Snap channel to install Kubernetes master services from
client_password:
type: string
default: ""
description: |
Password to be used for admin user (leave empty for random password).
Loading