Setup heptio authenticator

This commit is contained in:
Rodrigo Menezes 2018-05-23 17:48:33 -07:00
parent ee8252e323
commit 5ce8f9e712
8 changed files with 317 additions and 19 deletions

View File

@ -32,3 +32,84 @@ spec:
rbac: {}
```
## Heptio Authenticator for AWS
If you want to turn on Heptio Authenticator for AWS, you can add this block
to your cluster:
```
authentication:
heptio: {}
```
For example:
```
apiVersion: kops/v1alpha2
kind: Cluster
metadata:
name: cluster.example.com
spec:
authentication:
heptio: {}
authorization:
rbac: {}
```
Once the cluster is up you will need to create the heptio authenticator
config as a config map. (This can also be done when boostrapping a cluster using addons)
For more details on heptio authenticator please visit (heptio/authenticator)[https://github.com/heptio/authenticator]
Example config:
```
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: kube-system
name: heptio-authenticator-aws
labels:
k8s-app: heptio-authenticator-aws
data:
config.yaml: |
# a unique-per-cluster identifier to prevent replay attacks
# (good choices are a random token or a domain name that will be unique to your cluster)
clusterID: my-dev-cluster.example.com
server:
# each mapRoles entry maps an IAM role to a username and set of groups
# Each username and group can optionally contain template parameters:
# 1) "{{AccountID}}" is the 12 digit AWS ID.
# 2) "{{SessionName}}" is the role session name.
mapRoles:
# statically map arn:aws:iam::000000000000:role/KubernetesAdmin to a cluster admin
- roleARN: arn:aws:iam::000000000000:role/KubernetesAdmin
username: kubernetes-admin
groups:
- system:masters
# map EC2 instances in my "KubernetesNode" role to users like
# "aws:000000000000:instance:i-0123456789abcdef0". Only use this if you
# trust that the role can only be assumed by EC2 instances. If an IAM user
# can assume this role directly (with sts:AssumeRole) they can control
# SessionName.
- roleARN: arn:aws:iam::000000000000:role/KubernetesNode
username: aws:{{AccountID}}:instance:{{SessionName}}
groups:
- system:bootstrappers
- aws:instances
# map federated users in my "KubernetesAdmin" role to users like
# "admin:alice-example.com". The SessionName is an arbitrary role name
# like an e-mail address passed by the identity provider. Note that if this
# role is assumed directly by an IAM User (not via federation), the user
# can control the SessionName.
- roleARN: arn:aws:iam::000000000000:role/KubernetesAdmin
username: admin:{{SessionName}}
groups:
- system:masters
# each mapUsers entry maps an IAM role to a static username and set of groups
mapUsers:
# map user IAM user Alice in 000000000000 to user "alice" in "system:masters"
- userARN: arn:aws:iam::000000000000:user/Alice
username: alice
groups:
- system:masters
```

View File

@ -157,6 +157,103 @@ func (b *KubeAPIServerBuilder) writeAuthenticationConfig(c *fi.ModelBuilderConte
return nil
}
if b.Cluster.Spec.Authentication.Heptio != nil {
id := "heptio-authenticator-aws"
b.Cluster.Spec.KubeAPIServer.AuthenticationTokenWebhookConfigFile = fi.String(PathAuthnConfig)
{
caCertificate, err := b.NodeupModelContext.KeyStore.FindCert(fi.CertificateId_CA)
if err != nil {
return fmt.Errorf("error fetching Heptio Authentication CA certificate from keystore: %v", err)
}
if caCertificate == nil {
return fmt.Errorf("Heptio Authentication CA certificate %q not found", fi.CertificateId_CA)
}
cluster := kubeconfig.KubectlCluster{
Server: "https://127.0.0.1:21362/authenticate",
}
context := kubeconfig.KubectlContext{
Cluster: "heptio-authenticator-aws",
User: "kube-apiserver",
}
cluster.CertificateAuthorityData, err = caCertificate.AsBytes()
if err != nil {
return fmt.Errorf("error encoding Heptio Authentication CA certificate: %v", err)
}
config := kubeconfig.KubectlConfig{}
config.Clusters = append(config.Clusters, &kubeconfig.KubectlClusterWithName{
Name: "heptio-authenticator-aws",
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)
}
c.AddTask(&nodetasks.File{
Path: PathAuthnConfig,
Contents: fi.NewBytesResource(manifest),
Type: nodetasks.FileType_File,
})
}
{
certificate, err := b.NodeupModelContext.KeyStore.FindCert(id)
if err != nil {
return fmt.Errorf("error fetching %q certificate from keystore: %v", id, err)
}
if certificate == nil {
return fmt.Errorf("certificate %q not found", id)
}
certificateData, err := certificate.AsBytes()
if err != nil {
return fmt.Errorf("error encoding %q certificate: %v", id, err)
}
c.AddTask(&nodetasks.File{
Path: "/srv/kubernetes/heptio-authenticator-aws/cert.pem",
Contents: fi.NewBytesResource(certificateData),
Type: nodetasks.FileType_File,
})
}
{
privateKey, err := b.NodeupModelContext.KeyStore.FindPrivateKey(id)
if err != nil {
return fmt.Errorf("error fetching %q private key from keystore: %v", id, err)
}
if privateKey == nil {
return fmt.Errorf("private key %q not found", id)
}
keyData, err := privateKey.AsBytes()
if err != nil {
return fmt.Errorf("error encoding %q private key: %v", id, err)
}
c.AddTask(&nodetasks.File{
Path: "/srv/kubernetes/heptio-authenticator-aws/key.pem",
Contents: fi.NewBytesResource(keyData),
Type: nodetasks.FileType_File,
})
}
return nil
}
return fmt.Errorf("Unrecognized authentication config %v", b.Cluster.Spec.Authentication)
}
@ -311,7 +408,7 @@ func (b *KubeAPIServerBuilder) buildPod() (*v1.Pod, error) {
}
if b.Cluster.Spec.Authentication != nil {
if b.Cluster.Spec.Authentication.Kopeio != nil {
if b.Cluster.Spec.Authentication.Kopeio != nil || b.Cluster.Spec.Authentication.Heptio != nil {
addHostPathMapping(pod, container, "authn-config", PathAuthnConfig)
}
}

View File

@ -230,15 +230,19 @@ type ExecContainerAction struct {
type AuthenticationSpec struct {
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
Heptio *HeptioAuthenticationSpec `json:"heptio,omitempty"`
}
func (s *AuthenticationSpec) IsEmpty() bool {
return s.Kopeio == nil
return s.Kopeio == nil && s.Heptio == nil
}
type KopeioAuthenticationSpec struct {
}
type HeptioAuthenticationSpec struct {
}
type AuthorizationSpec struct {
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`

View File

@ -229,15 +229,19 @@ type ExecContainerAction struct {
type AuthenticationSpec struct {
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
Heptio *HeptioAuthenticationSpec `json:"heptio,omitempty"`
}
func (s *AuthenticationSpec) IsEmpty() bool {
return s.Kopeio == nil
return s.Kopeio == nil && s.Heptio == nil
}
type KopeioAuthenticationSpec struct {
}
type HeptioAuthenticationSpec struct {
}
type AuthorizationSpec struct {
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`

View File

@ -230,15 +230,19 @@ type ExecContainerAction struct {
type AuthenticationSpec struct {
Kopeio *KopeioAuthenticationSpec `json:"kopeio,omitempty"`
Heptio *HeptioAuthenticationSpec `json:"heptio,omitempty"`
}
func (s *AuthenticationSpec) IsEmpty() bool {
return s.Kopeio == nil
return s.Kopeio == nil && s.Heptio == nil
}
type KopeioAuthenticationSpec struct {
}
type HeptioAuthenticationSpec struct {
}
type AuthorizationSpec struct {
AlwaysAllow *AlwaysAllowAuthorizationSpec `json:"alwaysAllow,omitempty"`
RBAC *RBACAuthorizationSpec `json:"rbac,omitempty"`

View File

@ -260,6 +260,25 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
c.AddTask(t)
}
if b.Cluster.Spec.Authentication != nil {
if b.KopsModelContext.Cluster.Spec.Authentication.Heptio != nil {
alternateNames := []string{
"localhost",
"127.0.0.1",
}
t := &fitasks.Keypair{
Name: fi.String("heptio-authenticator-aws"),
Subject: "cn=heptio-authenticator-aws",
Type: "server",
AlternateNames: alternateNames,
Signer: defaultCA,
Format: format,
}
c.AddTask(t)
}
}
// Create auth tokens (though this is deprecated)
for _, x := range tokens.GetKubernetesAuthTokens_Deprecated() {
t := &fitasks.Secret{Name: fi.String(x), Lifecycle: b.Lifecycle}

View File

@ -0,0 +1,68 @@
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
namespace: kube-system
name: heptio-authenticator-aws
labels:
k8s-app: heptio-authenticator-aws
spec:
updateStrategy:
type: RollingUpdate
template:
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
labels:
k8s-app: heptio-authenticator-aws
spec:
# run on the host network (don't depend on CNI)
hostNetwork: true
# run on each master node
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
- key: CriticalAddonsOnly
operator: Exists
# run `heptio-authenticator-aws server` with three volumes
# - config (mounted from the ConfigMap at /etc/heptio-authenticator-aws/config.yaml)
# - state (persisted TLS certificate and keys, mounted from the host)
# - output (output kubeconfig to plug into your apiserver configuration, mounted from the host)
containers:
- name: heptio-authenticator-aws
image: gcr.io/heptio-images/authenticator:v0.1.0
args:
- server
- --config=/etc/heptio-authenticator-aws/config.yaml
- --state-dir=/var/heptio-authenticator-aws
resources:
requests:
memory: 20Mi
cpu: 10m
limits:
memory: 20Mi
cpu: 100m
volumeMounts:
- name: config
mountPath: /etc/heptio-authenticator-aws/
- name: state
mountPath: /var/heptio-authenticator-aws/
- name: output
mountPath: /etc/kubernetes/heptio-authenticator-aws/
volumes:
- name: config
configMap:
name: heptio-authenticator-aws
- name: output
hostPath:
path: /srv/kubernetes/heptio-authenticator-aws/
- name: state
hostPath:
path: /srv/kubernetes/heptio-authenticator-aws/

View File

@ -723,23 +723,44 @@ 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.20171125"
if b.cluster.Spec.Authentication != nil {
if b.cluster.Spec.Authentication.Kopeio != nil {
key := "authentication.kope.io"
version := "1.0.20171125"
{
location := key + "/k8s-1.8.yaml"
id := "k8s-1.8"
{
location := key + "/k8s-1.8.yaml"
id := "k8s-1.8"
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.8.0",
Id: id,
})
manifests[key+"-"+id] = "addons/" + location
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.8.0",
Id: id,
})
manifests[key+"-"+id] = "addons/" + location
}
}
if b.cluster.Spec.Authentication.Heptio != nil {
key := "authentication.hept.io"
version := "0.1.0"
{
location := key + "/k8s-1.10.yaml"
id := "k8s-1.10"
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.10.0",
Id: id,
})
manifests[key+"-"+id] = "addons/" + location
}
}
}