Merge pull request #2773 from justinsb/authn_integration

Initial support for authentication (kopeio)
This commit is contained in:
Chris Love 2017-07-06 14:11:22 -06:00 committed by GitHub
commit 20535248b4
9 changed files with 409 additions and 0 deletions

View File

@ -25,11 +25,15 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/flagbuilder"
"k8s.io/kops/pkg/kubeconfig"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
)
const PathAuthnConfig = "/etc/kubernetes/authn.config"
// KubeAPIServerBuilder install kube-apiserver (just the manifest at the moment)
type KubeAPIServerBuilder struct {
*NodeupModelContext
@ -42,6 +46,11 @@ func (b *KubeAPIServerBuilder) Build(c *fi.ModelBuilderContext) error {
return nil
}
err := b.writeAuthenticationConfig(c)
if err != nil {
return err
}
{
pod, err := b.buildPod()
if err != nil {
@ -76,6 +85,54 @@ func (b *KubeAPIServerBuilder) Build(c *fi.ModelBuilderContext) error {
return nil
}
func (b *KubeAPIServerBuilder) writeAuthenticationConfig(c *fi.ModelBuilderContext) error {
if b.Cluster.Spec.Authentication == nil || b.Cluster.Spec.Authentication.IsEmpty() {
return nil
}
if b.Cluster.Spec.Authentication.Kopeio != nil {
cluster := kubeconfig.KubectlCluster{
Server: "http://127.0.0.1:9001/hooks/authn",
}
context := kubeconfig.KubectlContext{
Cluster: "webhook",
User: "kube-apiserver",
}
config := kubeconfig.KubectlConfig{
Kind: "Config",
ApiVersion: "v1",
}
config.Clusters = append(config.Clusters, &kubeconfig.KubectlClusterWithName{
Name: "webhook",
Cluster: cluster,
})
config.Users = append(config.Users, &kubeconfig.KubectlUserWithName{
Name: "kube-apiserver",
})
config.CurrentContext = "webhook"
config.Contexts = append(config.Contexts, &kubeconfig.KubectlContextWithName{
Name: "webhook",
Context: context,
})
manifest, err := kops.ToRawYaml(config)
if err != nil {
return fmt.Errorf("error marshalling authentication config to yaml: %v", err)
}
t := &nodetasks.File{
Path: PathAuthnConfig,
Contents: fi.NewBytesResource(manifest),
Type: nodetasks.FileType_File,
}
c.AddTask(t)
return nil
} else {
return fmt.Errorf("Unrecognized authentication config %v", b.Cluster.Spec.Authentication)
}
}
func (b *KubeAPIServerBuilder) buildPod() (*v1.Pod, error) {
kubeAPIServer := b.Cluster.Spec.KubeAPIServer
@ -192,6 +249,12 @@ func (b *KubeAPIServerBuilder) buildPod() (*v1.Pod, error) {
addHostPathMapping(pod, container, "auditlogpathdir", auditLogPathDir).ReadOnly = false
}
if b.Cluster.Spec.Authentication != nil {
if b.Cluster.Spec.Authentication.Kopeio != nil {
addHostPathMapping(pod, container, "authn-config", PathAuthnConfig)
}
}
pod.Spec.Containers = append(pod.Spec.Containers, *container)
return pod, nil

View File

@ -238,6 +238,9 @@ type ClusterSpec struct {
// API field controls how the API is exposed outside the cluster
API *AccessSpec `json:"api,omitempty"`
// Authentication field controls how the cluster is configured for authentication
Authentication *AuthenticationSpec `json:"authentication,omitempty"`
// Authorization field controls how the cluster is configured for authorization
Authorization *AuthorizationSpec `json:"authorization,omitempty"`
@ -259,6 +262,17 @@ type ExecContainerAction struct {
Command []string `json:"command,omitempty"`
}
type AuthenticationSpec struct {
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
}
func (s *AuthenticationSpec) IsEmpty() bool {
return s.Kopeio == nil
}
type KopeioAuthenticationSpec struct {
}
type AuthorizationSpec struct {
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`

View File

@ -232,6 +232,9 @@ type ClusterSpec struct {
// API field controls how the API is exposed outside the cluster
API *AccessSpec `json:"api,omitempty"`
// Authentication field controls how the cluster is configured for authentication
Authentication *AuthenticationSpec `json:"authentication,omitempty"`
// Authorization field controls how the cluster is configured for authorization
Authorization *AuthorizationSpec `json:"authorization,omitempty"`
@ -253,6 +256,17 @@ type ExecContainerAction struct {
Command []string `json:"command,omitempty"`
}
type AuthenticationSpec struct {
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
}
func (s *AuthenticationSpec) IsEmpty() bool {
return s.Kopeio == nil
}
type KopeioAuthenticationSpec struct {
}
type AuthorizationSpec struct {
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`

View File

@ -39,6 +39,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_AccessSpec_To_v1alpha1_AccessSpec,
Convert_v1alpha1_AlwaysAllowAuthorizationSpec_To_kops_AlwaysAllowAuthorizationSpec,
Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizationSpec,
Convert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec,
Convert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec,
Convert_v1alpha1_AuthorizationSpec_To_kops_AuthorizationSpec,
Convert_kops_AuthorizationSpec_To_v1alpha1_AuthorizationSpec,
Convert_v1alpha1_CNINetworkingSpec_To_kops_CNINetworkingSpec,
@ -87,6 +89,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_InstanceGroupList_To_v1alpha1_InstanceGroupList,
Convert_v1alpha1_InstanceGroupSpec_To_kops_InstanceGroupSpec,
Convert_kops_InstanceGroupSpec_To_v1alpha1_InstanceGroupSpec,
Convert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec,
Convert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec,
Convert_v1alpha1_KopeioNetworkingSpec_To_kops_KopeioNetworkingSpec,
Convert_kops_KopeioNetworkingSpec_To_v1alpha1_KopeioNetworkingSpec,
Convert_v1alpha1_KubeAPIServerConfig_To_kops_KubeAPIServerConfig,
@ -190,6 +194,40 @@ func Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizat
return autoConvert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizationSpec(in, out, s)
}
func autoConvert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(in *AuthenticationSpec, out *kops.AuthenticationSpec, s conversion.Scope) error {
if in.Kopeio != nil {
in, out := &in.Kopeio, &out.Kopeio
*out = new(kops.KopeioAuthenticationSpec)
if err := Convert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Kopeio = nil
}
return nil
}
func Convert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(in *AuthenticationSpec, out *kops.AuthenticationSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(in, out, s)
}
func autoConvert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(in *kops.AuthenticationSpec, out *AuthenticationSpec, s conversion.Scope) error {
if in.Kopeio != nil {
in, out := &in.Kopeio, &out.Kopeio
*out = new(KopeioAuthenticationSpec)
if err := Convert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Kopeio = nil
}
return nil
}
func Convert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(in *kops.AuthenticationSpec, out *AuthenticationSpec, s conversion.Scope) error {
return autoConvert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(in, out, s)
}
func autoConvert_v1alpha1_AuthorizationSpec_To_kops_AuthorizationSpec(in *AuthorizationSpec, out *kops.AuthorizationSpec, s conversion.Scope) error {
if in.AlwaysAllow != nil {
in, out := &in.AlwaysAllow, &out.AlwaysAllow
@ -569,6 +607,15 @@ func autoConvert_v1alpha1_ClusterSpec_To_kops_ClusterSpec(in *ClusterSpec, out *
} else {
out.API = nil
}
if in.Authentication != nil {
in, out := &in.Authentication, &out.Authentication
*out = new(kops.AuthenticationSpec)
if err := Convert_v1alpha1_AuthenticationSpec_To_kops_AuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Authentication = nil
}
if in.Authorization != nil {
in, out := &in.Authorization, &out.Authorization
*out = new(kops.AuthorizationSpec)
@ -736,6 +783,15 @@ func autoConvert_kops_ClusterSpec_To_v1alpha1_ClusterSpec(in *kops.ClusterSpec,
} else {
out.API = nil
}
if in.Authentication != nil {
in, out := &in.Authentication, &out.Authentication
*out = new(AuthenticationSpec)
if err := Convert_kops_AuthenticationSpec_To_v1alpha1_AuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Authentication = nil
}
if in.Authorization != nil {
in, out := &in.Authorization, &out.Authorization
*out = new(AuthorizationSpec)
@ -1218,6 +1274,22 @@ func autoConvert_kops_InstanceGroupSpec_To_v1alpha1_InstanceGroupSpec(in *kops.I
return nil
}
func autoConvert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in *KopeioAuthenticationSpec, out *kops.KopeioAuthenticationSpec, s conversion.Scope) error {
return nil
}
func Convert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in *KopeioAuthenticationSpec, out *kops.KopeioAuthenticationSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in, out, s)
}
func autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec(in *kops.KopeioAuthenticationSpec, out *KopeioAuthenticationSpec, s conversion.Scope) error {
return nil
}
func Convert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec(in *kops.KopeioAuthenticationSpec, out *KopeioAuthenticationSpec, s conversion.Scope) error {
return autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha1_KopeioAuthenticationSpec(in, out, s)
}
func autoConvert_v1alpha1_KopeioNetworkingSpec_To_kops_KopeioNetworkingSpec(in *KopeioNetworkingSpec, out *kops.KopeioNetworkingSpec, s conversion.Scope) error {
return nil
}

View File

@ -158,6 +158,9 @@ type ClusterSpec struct {
// API field controls how the API is exposed outside the cluster
API *AccessSpec `json:"api,omitempty"`
// Authentication field controls how the cluster is configured for authentication
Authentication *AuthenticationSpec `json:"authentication,omitempty"`
// Authorization field controls how the cluster is configured for authorization
Authorization *AuthorizationSpec `json:"authorization,omitempty"`
@ -179,6 +182,17 @@ type ExecContainerAction struct {
Command []string `json:"command,omitempty"`
}
type AuthenticationSpec struct {
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
}
func (s *AuthenticationSpec) IsEmpty() bool {
return s.Kopeio == nil
}
type KopeioAuthenticationSpec struct {
}
type AuthorizationSpec struct {
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`

View File

@ -39,6 +39,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_AccessSpec_To_v1alpha2_AccessSpec,
Convert_v1alpha2_AlwaysAllowAuthorizationSpec_To_kops_AlwaysAllowAuthorizationSpec,
Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizationSpec,
Convert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec,
Convert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec,
Convert_v1alpha2_AuthorizationSpec_To_kops_AuthorizationSpec,
Convert_kops_AuthorizationSpec_To_v1alpha2_AuthorizationSpec,
Convert_v1alpha2_BastionSpec_To_kops_BastionSpec,
@ -91,6 +93,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_InstanceGroupList_To_v1alpha2_InstanceGroupList,
Convert_v1alpha2_InstanceGroupSpec_To_kops_InstanceGroupSpec,
Convert_kops_InstanceGroupSpec_To_v1alpha2_InstanceGroupSpec,
Convert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec,
Convert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec,
Convert_v1alpha2_KopeioNetworkingSpec_To_kops_KopeioNetworkingSpec,
Convert_kops_KopeioNetworkingSpec_To_v1alpha2_KopeioNetworkingSpec,
Convert_v1alpha2_KubeAPIServerConfig_To_kops_KubeAPIServerConfig,
@ -196,6 +200,40 @@ func Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizat
return autoConvert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizationSpec(in, out, s)
}
func autoConvert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(in *AuthenticationSpec, out *kops.AuthenticationSpec, s conversion.Scope) error {
if in.Kopeio != nil {
in, out := &in.Kopeio, &out.Kopeio
*out = new(kops.KopeioAuthenticationSpec)
if err := Convert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Kopeio = nil
}
return nil
}
func Convert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(in *AuthenticationSpec, out *kops.AuthenticationSpec, s conversion.Scope) error {
return autoConvert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(in, out, s)
}
func autoConvert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(in *kops.AuthenticationSpec, out *AuthenticationSpec, s conversion.Scope) error {
if in.Kopeio != nil {
in, out := &in.Kopeio, &out.Kopeio
*out = new(KopeioAuthenticationSpec)
if err := Convert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Kopeio = nil
}
return nil
}
func Convert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(in *kops.AuthenticationSpec, out *AuthenticationSpec, s conversion.Scope) error {
return autoConvert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(in, out, s)
}
func autoConvert_v1alpha2_AuthorizationSpec_To_kops_AuthorizationSpec(in *AuthorizationSpec, out *kops.AuthorizationSpec, s conversion.Scope) error {
if in.AlwaysAllow != nil {
in, out := &in.AlwaysAllow, &out.AlwaysAllow
@ -607,6 +645,15 @@ func autoConvert_v1alpha2_ClusterSpec_To_kops_ClusterSpec(in *ClusterSpec, out *
} else {
out.API = nil
}
if in.Authentication != nil {
in, out := &in.Authentication, &out.Authentication
*out = new(kops.AuthenticationSpec)
if err := Convert_v1alpha2_AuthenticationSpec_To_kops_AuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Authentication = nil
}
if in.Authorization != nil {
in, out := &in.Authorization, &out.Authorization
*out = new(kops.AuthorizationSpec)
@ -789,6 +836,15 @@ func autoConvert_kops_ClusterSpec_To_v1alpha2_ClusterSpec(in *kops.ClusterSpec,
} else {
out.API = nil
}
if in.Authentication != nil {
in, out := &in.Authentication, &out.Authentication
*out = new(AuthenticationSpec)
if err := Convert_kops_AuthenticationSpec_To_v1alpha2_AuthenticationSpec(*in, *out, s); err != nil {
return err
}
} else {
out.Authentication = nil
}
if in.Authorization != nil {
in, out := &in.Authorization, &out.Authorization
*out = new(AuthorizationSpec)
@ -1326,6 +1382,22 @@ func Convert_kops_InstanceGroupSpec_To_v1alpha2_InstanceGroupSpec(in *kops.Insta
return autoConvert_kops_InstanceGroupSpec_To_v1alpha2_InstanceGroupSpec(in, out, s)
}
func autoConvert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in *KopeioAuthenticationSpec, out *kops.KopeioAuthenticationSpec, s conversion.Scope) error {
return nil
}
func Convert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in *KopeioAuthenticationSpec, out *kops.KopeioAuthenticationSpec, s conversion.Scope) error {
return autoConvert_v1alpha2_KopeioAuthenticationSpec_To_kops_KopeioAuthenticationSpec(in, out, s)
}
func autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec(in *kops.KopeioAuthenticationSpec, out *KopeioAuthenticationSpec, s conversion.Scope) error {
return nil
}
func Convert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec(in *kops.KopeioAuthenticationSpec, out *KopeioAuthenticationSpec, s conversion.Scope) error {
return autoConvert_kops_KopeioAuthenticationSpec_To_v1alpha2_KopeioAuthenticationSpec(in, out, s)
}
func autoConvert_v1alpha2_KopeioNetworkingSpec_To_kops_KopeioNetworkingSpec(in *KopeioNetworkingSpec, out *kops.KopeioNetworkingSpec, s conversion.Scope) error {
return nil
}

View File

@ -77,6 +77,12 @@ func (b *KubeAPIServerOptionsBuilder) BuildOptions(o interface{}) error {
}
}
if clusterSpec.Authentication != nil {
if clusterSpec.Authentication.Kopeio != nil {
c.AuthenticationTokenWebhookConfigFile = fi.String("/etc/kubernetes/authn.config")
}
}
if clusterSpec.Authorization == nil || clusterSpec.Authorization.IsEmpty() {
// Do nothing - use the default as defined by the apiserver
// (this won't happen anyway because of our default logic)

View File

@ -0,0 +1,132 @@
apiVersion: v1
kind: Namespace
metadata:
name: kopeio-auth
labels:
k8s-addon: authentication.kope.io
role.kubernetes.io/authentication: "1"
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: auth-portal
namespace: kopeio-auth
labels:
k8s-addon: authentication.kope.io
role.kubernetes.io/authentication: "1"
spec:
template:
metadata:
labels:
app: auth-portal
spec:
containers:
- name: auth-portal
image: kopeio/auth-portal:1.0.20170619
ports:
- containerPort: 8080
command:
- /auth-portal
---
apiVersion: v1
kind: Service
metadata:
name: auth-portal
namespace: kopeio-auth
labels:
k8s-addon: authentication.kope.io
role.kubernetes.io/authentication: "1"
spec:
selector:
app: auth-portal
ports:
- port: 80
targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: auth-api
namespace: kopeio-auth
labels:
k8s-addon: authentication.kope.io
role.kubernetes.io/authentication: "1"
spec:
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: auth-api
spec:
hostNetwork: true
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
containers:
- name: auth-api
image: kopeio/auth-api:1.0.20170619
imagePullPolicy: Always
ports:
- containerPort: 9001
command:
- /auth-api
- --listen=127.0.0.1:9001
- --secure-port=9002
- --server=https://127.0.0.1:9002
- --insecure-skip-tls-verify
- --etcd-servers=http://127.0.0.1:4001
- --v=8
- --storage-backend=etcd2
---
apiVersion: v1
kind: Service
metadata:
name: auth-api
namespace: kopeio-auth
spec:
selector:
app: auth-api
ports:
- port: 443
targetPort: 9002
---
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: v1alpha1.auth.kope.io
spec:
insecureSkipTLSVerify: true
group: auth.kope.io
priority: 150
service:
name: auth-api
namespace: kopeio-auth
version: v1alpha1
---
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: v1alpha1.config.auth.kope.io
spec:
insecureSkipTLSVerify: true
group: config.auth.kope.io
priority: 150
service:
name: auth-api
namespace: kopeio-auth
version: v1alpha1

View File

@ -442,5 +442,27 @@ func (b *BootstrapChannelBuilder) buildManifest() (*channelsapi.Addons, map[stri
}
}
authenticationSelector := map[string]string{"role.kubernetes.io/authentication": "1"}
if b.cluster.Spec.Authentication != nil && b.cluster.Spec.Authentication.Kopeio != nil {
key := "authentication.kope.io"
version := "1.0.20170619"
{
location := key + "/k8s-1.6.yaml"
id := "k8s-1.6"
addons.Spec.Addons = append(addons.Spec.Addons, &channelsapi.AddonSpec{
Name: fi.String(key),
Version: fi.String(version),
Selector: authenticationSelector,
Manifest: fi.String(location),
KubernetesVersion: ">=1.6.0",
Id: id,
})
manifests[key+"-"+id] = "addons/" + location
}
}
return addons, manifests, nil
}