Merge pull request #12538 from hierynomus/issue-12205

Configure aws-iam-authenticator using identityMappings defined in cluster.yaml
This commit is contained in:
Kubernetes Prow Robot 2021-10-29 03:10:51 -07:00 committed by GitHub
commit 59a637e6de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 721 additions and 6 deletions

View File

@ -55,10 +55,10 @@ spec:
rbac: {}
```
By default the creation of an AWS IAM authenticator config as a ConfigMap is also required.
If no `backendMode` is configured, by default the `aws-iam-authenticator` will require the creation of an AWS IAM authenticator config as a ConfigMap.
For more details on AWS IAM authenticator please visit [kubernetes-sigs/aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator)
Example config:
Example config using a ConfigMap:
```yaml
---
@ -124,13 +124,34 @@ authentication:
clusterID: demo.cluster.us-west-2
```
When setting the `backendMode` configuration to `CRD`, it is possible to provide a list of inline AWS IAM identity mappings in the cluster template.
```yaml
authentication:
aws:
backendMode: CRD
clusterID: demo.cluster.us-west-2
identityMappings:
- arn: arn:aws:iam::000000000000:role/KubernetesAdmin
username: admin:{{SessionName}}
groups:
- system:masters
- arn: arn:aws:iam::000000000000:user/Alice
username: alice
groups:
- system:masters
```
### Creating a new cluster with IAM Authenticator on.
* Create a cluster following the [AWS getting started guide](getting_started/aws.md)
* When you reach the "Customize Cluster Configuration" section of the guide modify the cluster spec and add the Authentication and Authorization configs to the YAML config.
* Optionally set the `backendMode: CRD` and configure the identityMappings inline.
* Continue following the cluster creation guide to build the cluster.
* :warning: When the cluster first comes up the aws-iam-authenticator PODs will be in a bad state.
as it is trying to find the aws-iam-authenticator ConfigMap and we have not yet created it.
* :warning: When no `backendMode` is configured (or it is set to `MountedFile`) and the cluster first comes up the aws-iam-authenticator PODs will be in a bad state as it is trying to find the aws-iam-authenticator ConfigMap and we have not yet created it.
If no `backendMode` is configured, or it is set to `MountedFile, the following additional steps are necessary:
* Once the cluster is up, you'll need to create an aws-iam-authenticator configMap on the cluster `kubectl apply -f aws-iam-authenticator_example-config.yaml`
* Once the configuration is created you need to delete the initially created aws-iam-authenticator PODs, this will force new ones to come and correctly find the ConfigMap.
```
@ -144,4 +165,4 @@ kubectl get pods -n kube-system | grep aws-iam-authenticator | awk '{print $1}'
* Update the clusters configuration `kops update cluster ${CLUSTER_NAME} --yes`
* Temporarily disable aws-iam-authenticator DaemonSet `kubectl patch daemonset -n kube-system aws-iam-authenticator -p '{"spec": {"template": {"spec": {"nodeSelector": {"disable-aws-iam-authenticator": "true"}}}}}'`
* Perform a rolling update of the masters `kops rolling-update cluster ${CLUSTER_NAME} --instance-group-roles=Master --force --yes`
* Re-enable aws-iam-authenticator DaemonSet `kubectl patch daemonset -n kube-system aws-iam-authenticator --type json -p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector/disable-aws-iam-authenticator"}]'`
* Re-enable aws-iam-authenticator DaemonSet `kubectl patch daemonset -n kube-system aws-iam-authenticator --type json -p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector/disable-aws-iam-authenticator"}]'`

View File

@ -205,6 +205,26 @@ spec:
container. Default 10m
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
identityMappings:
description: IdentityMappings maps IAM Identities to Kubernetes
users/groups
items:
properties:
arn:
description: Arn of the IAM User or IAM Role to be allowed
to authenticate
type: string
groups:
description: Groups to be attached to your users/roles
items:
type: string
type: array
username:
description: Username that Kubernetes will see the user
as
type: string
type: object
type: array
image:
description: Image is the AWS IAM Authenticator docker image
to uses

View File

@ -373,6 +373,17 @@ type AwsAuthenticationSpec struct {
MemoryLimit *resource.Quantity `json:"memoryLimit,omitempty"`
// CPULimit CPU limit of AWS IAM Authenticator container. Default 10m
CPULimit *resource.Quantity `json:"cpuLimit,omitempty"`
// IdentityMappings maps IAM Identities to Kubernetes users/groups
IdentityMappings []AwsAuthenticationIdentityMappingSpec `json:"identityMappings,omitempty"`
}
type AwsAuthenticationIdentityMappingSpec struct {
// Arn of the IAM User or IAM Role to be allowed to authenticate
ARN string `json:"arn,omitempty"`
// Username that Kubernetes will see the user as
Username string `json:"username,omitempty"`
// Groups to be attached to your users/roles
Groups []string `json:"groups,omitempty"`
}
type AuthorizationSpec struct {

View File

@ -371,6 +371,17 @@ type AwsAuthenticationSpec struct {
MemoryLimit *resource.Quantity `json:"memoryLimit,omitempty"`
// CPULimit CPU limit of AWS IAM Authenticator container. Default 10m
CPULimit *resource.Quantity `json:"cpuLimit,omitempty"`
// IdentityMappings maps IAM Identities to Kubernetes users/groups
IdentityMappings []AwsAuthenticationIdentityMappingSpec `json:"identityMappings,omitempty"`
}
type AwsAuthenticationIdentityMappingSpec struct {
// Arn of the IAM User or IAM Role to be allowed to authenticate
ARN string `json:"arn,omitempty"`
// Username that Kubernetes will see the user as
Username string `json:"username,omitempty"`
// Groups to be attached to your users/roles
Groups []string `json:"groups,omitempty"`
}
type AuthorizationSpec struct {

View File

@ -144,6 +144,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*AwsAuthenticationIdentityMappingSpec)(nil), (*kops.AwsAuthenticationIdentityMappingSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha2_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(a.(*AwsAuthenticationIdentityMappingSpec), b.(*kops.AwsAuthenticationIdentityMappingSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kops.AwsAuthenticationIdentityMappingSpec)(nil), (*AwsAuthenticationIdentityMappingSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha2_AwsAuthenticationIdentityMappingSpec(a.(*kops.AwsAuthenticationIdentityMappingSpec), b.(*AwsAuthenticationIdentityMappingSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*AwsAuthenticationSpec)(nil), (*kops.AwsAuthenticationSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha2_AwsAuthenticationSpec_To_kops_AwsAuthenticationSpec(a.(*AwsAuthenticationSpec), b.(*kops.AwsAuthenticationSpec), scope)
}); err != nil {
@ -1507,6 +1517,30 @@ func Convert_kops_AuthorizationSpec_To_v1alpha2_AuthorizationSpec(in *kops.Autho
return autoConvert_kops_AuthorizationSpec_To_v1alpha2_AuthorizationSpec(in, out, s)
}
func autoConvert_v1alpha2_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(in *AwsAuthenticationIdentityMappingSpec, out *kops.AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
out.ARN = in.ARN
out.Username = in.Username
out.Groups = in.Groups
return nil
}
// Convert_v1alpha2_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec is an autogenerated conversion function.
func Convert_v1alpha2_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(in *AwsAuthenticationIdentityMappingSpec, out *kops.AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
return autoConvert_v1alpha2_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(in, out, s)
}
func autoConvert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha2_AwsAuthenticationIdentityMappingSpec(in *kops.AwsAuthenticationIdentityMappingSpec, out *AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
out.ARN = in.ARN
out.Username = in.Username
out.Groups = in.Groups
return nil
}
// Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha2_AwsAuthenticationIdentityMappingSpec is an autogenerated conversion function.
func Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha2_AwsAuthenticationIdentityMappingSpec(in *kops.AwsAuthenticationIdentityMappingSpec, out *AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
return autoConvert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha2_AwsAuthenticationIdentityMappingSpec(in, out, s)
}
func autoConvert_v1alpha2_AwsAuthenticationSpec_To_kops_AwsAuthenticationSpec(in *AwsAuthenticationSpec, out *kops.AwsAuthenticationSpec, s conversion.Scope) error {
out.Image = in.Image
out.BackendMode = in.BackendMode
@ -1515,6 +1549,17 @@ func autoConvert_v1alpha2_AwsAuthenticationSpec_To_kops_AwsAuthenticationSpec(in
out.CPURequest = in.CPURequest
out.MemoryLimit = in.MemoryLimit
out.CPULimit = in.CPULimit
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]kops.AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
if err := Convert_v1alpha2_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.IdentityMappings = nil
}
return nil
}
@ -1531,6 +1576,17 @@ func autoConvert_kops_AwsAuthenticationSpec_To_v1alpha2_AwsAuthenticationSpec(in
out.CPURequest = in.CPURequest
out.MemoryLimit = in.MemoryLimit
out.CPULimit = in.CPULimit
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
if err := Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha2_AwsAuthenticationIdentityMappingSpec(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.IdentityMappings = nil
}
return nil
}

View File

@ -284,6 +284,27 @@ func (in *AuthorizationSpec) DeepCopy() *AuthorizationSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AwsAuthenticationIdentityMappingSpec) DeepCopyInto(out *AwsAuthenticationIdentityMappingSpec) {
*out = *in
if in.Groups != nil {
in, out := &in.Groups, &out.Groups
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsAuthenticationIdentityMappingSpec.
func (in *AwsAuthenticationIdentityMappingSpec) DeepCopy() *AwsAuthenticationIdentityMappingSpec {
if in == nil {
return nil
}
out := new(AwsAuthenticationIdentityMappingSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AwsAuthenticationSpec) DeepCopyInto(out *AwsAuthenticationSpec) {
*out = *in
@ -307,6 +328,13 @@ func (in *AwsAuthenticationSpec) DeepCopyInto(out *AwsAuthenticationSpec) {
x := (*in).DeepCopy()
*out = &x
}
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}

View File

@ -345,6 +345,17 @@ type AwsAuthenticationSpec struct {
MemoryLimit *resource.Quantity `json:"memoryLimit,omitempty"`
// CPULimit CPU limit of AWS IAM Authenticator container. Default 10m
CPULimit *resource.Quantity `json:"cpuLimit,omitempty"`
// IdentityMappings maps IAM Identities to Kubernetes users/groups
IdentityMappings []AwsAuthenticationIdentityMappingSpec `json:"identityMappings,omitempty"`
}
type AwsAuthenticationIdentityMappingSpec struct {
// Arn of the IAM User or IAM Role to be allowed to authenticate
ARN string `json:"arn,omitempty"`
// Username that Kubernetes will see the user as
Username string `json:"username,omitempty"`
// Groups to be attached to your users/roles
Groups []string `json:"groups,omitempty"`
}
type AuthorizationSpec struct {

View File

@ -144,6 +144,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*AwsAuthenticationIdentityMappingSpec)(nil), (*kops.AwsAuthenticationIdentityMappingSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha3_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(a.(*AwsAuthenticationIdentityMappingSpec), b.(*kops.AwsAuthenticationIdentityMappingSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kops.AwsAuthenticationIdentityMappingSpec)(nil), (*AwsAuthenticationIdentityMappingSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha3_AwsAuthenticationIdentityMappingSpec(a.(*kops.AwsAuthenticationIdentityMappingSpec), b.(*AwsAuthenticationIdentityMappingSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*AwsAuthenticationSpec)(nil), (*kops.AwsAuthenticationSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha3_AwsAuthenticationSpec_To_kops_AwsAuthenticationSpec(a.(*AwsAuthenticationSpec), b.(*kops.AwsAuthenticationSpec), scope)
}); err != nil {
@ -1457,6 +1467,30 @@ func Convert_kops_AuthorizationSpec_To_v1alpha3_AuthorizationSpec(in *kops.Autho
return autoConvert_kops_AuthorizationSpec_To_v1alpha3_AuthorizationSpec(in, out, s)
}
func autoConvert_v1alpha3_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(in *AwsAuthenticationIdentityMappingSpec, out *kops.AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
out.ARN = in.ARN
out.Username = in.Username
out.Groups = in.Groups
return nil
}
// Convert_v1alpha3_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec is an autogenerated conversion function.
func Convert_v1alpha3_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(in *AwsAuthenticationIdentityMappingSpec, out *kops.AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
return autoConvert_v1alpha3_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(in, out, s)
}
func autoConvert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha3_AwsAuthenticationIdentityMappingSpec(in *kops.AwsAuthenticationIdentityMappingSpec, out *AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
out.ARN = in.ARN
out.Username = in.Username
out.Groups = in.Groups
return nil
}
// Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha3_AwsAuthenticationIdentityMappingSpec is an autogenerated conversion function.
func Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha3_AwsAuthenticationIdentityMappingSpec(in *kops.AwsAuthenticationIdentityMappingSpec, out *AwsAuthenticationIdentityMappingSpec, s conversion.Scope) error {
return autoConvert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha3_AwsAuthenticationIdentityMappingSpec(in, out, s)
}
func autoConvert_v1alpha3_AwsAuthenticationSpec_To_kops_AwsAuthenticationSpec(in *AwsAuthenticationSpec, out *kops.AwsAuthenticationSpec, s conversion.Scope) error {
out.Image = in.Image
out.BackendMode = in.BackendMode
@ -1465,6 +1499,17 @@ func autoConvert_v1alpha3_AwsAuthenticationSpec_To_kops_AwsAuthenticationSpec(in
out.CPURequest = in.CPURequest
out.MemoryLimit = in.MemoryLimit
out.CPULimit = in.CPULimit
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]kops.AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
if err := Convert_v1alpha3_AwsAuthenticationIdentityMappingSpec_To_kops_AwsAuthenticationIdentityMappingSpec(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.IdentityMappings = nil
}
return nil
}
@ -1481,6 +1526,17 @@ func autoConvert_kops_AwsAuthenticationSpec_To_v1alpha3_AwsAuthenticationSpec(in
out.CPURequest = in.CPURequest
out.MemoryLimit = in.MemoryLimit
out.CPULimit = in.CPULimit
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
if err := Convert_kops_AwsAuthenticationIdentityMappingSpec_To_v1alpha3_AwsAuthenticationIdentityMappingSpec(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.IdentityMappings = nil
}
return nil
}

View File

@ -285,6 +285,27 @@ func (in *AuthorizationSpec) DeepCopy() *AuthorizationSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AwsAuthenticationIdentityMappingSpec) DeepCopyInto(out *AwsAuthenticationIdentityMappingSpec) {
*out = *in
if in.Groups != nil {
in, out := &in.Groups, &out.Groups
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsAuthenticationIdentityMappingSpec.
func (in *AwsAuthenticationIdentityMappingSpec) DeepCopy() *AwsAuthenticationIdentityMappingSpec {
if in == nil {
return nil
}
out := new(AwsAuthenticationIdentityMappingSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AwsAuthenticationSpec) DeepCopyInto(out *AwsAuthenticationSpec) {
*out = *in
@ -308,6 +329,13 @@ func (in *AwsAuthenticationSpec) DeepCopyInto(out *AwsAuthenticationSpec) {
x := (*in).DeepCopy()
*out = &x
}
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}

View File

@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/ec2"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
@ -43,6 +44,10 @@ func awsValidateCluster(c *kops.Cluster) field.ErrorList {
allErrs = append(allErrs, awsValidateExternalCloudControllerManager(c)...)
if c.Spec.Authentication != nil && c.Spec.Authentication.Aws != nil {
allErrs = append(allErrs, awsValidateIAMAuthenticator(field.NewPath("spec", "authentication", "aws"), c.Spec.Authentication.Aws)...)
}
return allErrs
}
@ -319,6 +324,22 @@ func awsValidateCPUCredits(fieldPath *field.Path, spec *kops.InstanceGroupSpec,
return allErrs
}
func awsValidateIAMAuthenticator(fieldPath *field.Path, spec *kops.AwsAuthenticationSpec) field.ErrorList {
allErrs := field.ErrorList{}
if !strings.Contains(spec.BackendMode, "CRD") && len(spec.IdentityMappings) > 0 {
allErrs = append(allErrs, field.Forbidden(fieldPath.Child("backendMode"), "backendMode must be CRD if identityMappings is set"))
}
for i, mapping := range spec.IdentityMappings {
parsedARN, err := arn.Parse(mapping.ARN)
if err != nil || (!strings.HasPrefix(parsedARN.Resource, "role/") && !strings.HasPrefix(parsedARN.Resource, "user/")) {
allErrs = append(allErrs, field.Invalid(fieldPath.Child("identityMappings").Index(i).Child("arn"), mapping.ARN,
"arn must be a valid IAM Role or User ARN such as arn:aws:iam::123456789012:role/KopsExampleRole"))
}
}
return allErrs
}
func hasAWSEBSCSIDriver(c kops.ClusterSpec) bool {
// AWSEBSCSIDriver will have a default value, so if this is all false, it will be populated on next pass
if c.CloudConfig == nil || c.CloudConfig.AWSEBSCSIDriver == nil || c.CloudConfig.AWSEBSCSIDriver.Enabled == nil {

View File

@ -575,3 +575,73 @@ func TestLoadBalancerSubnets(t *testing.T) {
testErrors(t, test, errs, test.expected)
}
}
func TestAWSAuthentication(t *testing.T) {
tests := []struct {
backendMode string
identityMappings []kops.AwsAuthenticationIdentityMappingSpec
expected []string
}{
{ // valid
backendMode: "CRD",
identityMappings: []kops.AwsAuthenticationIdentityMappingSpec{
{
ARN: "arn:aws:iam::123456789012:role/KopsExampleRole",
Username: "foo",
},
{
ARN: "arn:aws:iam::123456789012:user/KopsExampleUser",
Username: "foo",
},
},
},
{ // valid, multiple backendModes
backendMode: "CRD,MountedFile",
identityMappings: []kops.AwsAuthenticationIdentityMappingSpec{
{
ARN: "arn:aws:iam::123456789012:role/KopsExampleRole",
Username: "foo",
},
{
ARN: "arn:aws:iam::123456789012:user/KopsExampleUser",
Username: "foo",
},
},
},
{ // forbidden backendMode
backendMode: "MountedFile",
identityMappings: []kops.AwsAuthenticationIdentityMappingSpec{
{
ARN: "arn:aws:iam::123456789012:role/KopsExampleRole",
Username: "foo",
},
},
expected: []string{"Forbidden::spec.authentication.aws.backendMode"},
},
{ // invalid identity ARN
backendMode: "CRD",
identityMappings: []kops.AwsAuthenticationIdentityMappingSpec{
{
ARN: "arn:aws:iam::123456789012:policy/KopsExampleRole",
Username: "foo",
},
},
expected: []string{"Invalid value::spec.authentication.aws.identityMappings[0].arn"},
},
}
for _, test := range tests {
cluster := kops.Cluster{
Spec: kops.ClusterSpec{
Authentication: &kops.AuthenticationSpec{
Aws: &kops.AwsAuthenticationSpec{
BackendMode: test.backendMode,
IdentityMappings: test.identityMappings,
},
},
},
}
errs := awsValidateCluster(&cluster)
testErrors(t, test, errs, test.expected)
}
}

View File

@ -284,6 +284,27 @@ func (in *AuthorizationSpec) DeepCopy() *AuthorizationSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AwsAuthenticationIdentityMappingSpec) DeepCopyInto(out *AwsAuthenticationIdentityMappingSpec) {
*out = *in
if in.Groups != nil {
in, out := &in.Groups, &out.Groups
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsAuthenticationIdentityMappingSpec.
func (in *AwsAuthenticationIdentityMappingSpec) DeepCopy() *AwsAuthenticationIdentityMappingSpec {
if in == nil {
return nil
}
out := new(AwsAuthenticationIdentityMappingSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AwsAuthenticationSpec) DeepCopyInto(out *AwsAuthenticationSpec) {
*out = *in
@ -307,6 +328,13 @@ func (in *AwsAuthenticationSpec) DeepCopyInto(out *AwsAuthenticationSpec) {
x := (*in).DeepCopy()
*out = &x
}
if in.IdentityMappings != nil {
in, out := &in.IdentityMappings, &out.IdentityMappings
*out = make([]AwsAuthenticationIdentityMappingSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}

View File

@ -205,3 +205,19 @@ spec:
- name: state
hostPath:
path: /srv/kubernetes/aws-iam-authenticator/
{{- if and (and (.Authentication.Aws.BackendMode) (contains "CRD" .Authentication.Aws.BackendMode)) (.Authentication.Aws.IdentityMappings) }}
---
{{- range $i, $mapping := .Authentication.Aws.IdentityMappings }}
apiVersion: iamauthenticator.k8s.aws/v1alpha1
kind: IAMIdentityMapping
metadata:
name: iam-identity-mapping-{{ $i }}
labels:
k8s-app: aws-iam-authenticator
spec:
arn: {{ $mapping.ARN }}
username: {{ $mapping.Username }}
groups:
{{ ToYAML $mapping.Groups | indent 4 }}
{{- end }}
{{- end }}

View File

@ -50,7 +50,8 @@ func TestBootstrapChannelBuilder_BuildTasks(t *testing.T) {
runChannelBuilderTest(t, "weave", []string{})
runChannelBuilderTest(t, "amazonvpc", []string{"networking.amazon-vpc-routed-eni-k8s-1.16"})
runChannelBuilderTest(t, "amazonvpc-containerd", []string{"networking.amazon-vpc-routed-eni-k8s-1.16"})
runChannelBuilderTest(t, "awsiamauthenticator", []string{"authentication.aws-k8s-1.12"})
runChannelBuilderTest(t, "awsiamauthenticator/crd", []string{"authentication.aws-k8s-1.12"})
runChannelBuilderTest(t, "awsiamauthenticator/mappings", []string{"authentication.aws-k8s-1.12"})
runChannelBuilderTest(t, "metrics-server/insecure-1.18", []string{"metrics-server.addons.k8s.io-k8s-1.11"})
runChannelBuilderTest(t, "metrics-server/insecure-1.19", []string{"metrics-server.addons.k8s.io-k8s-1.11"})
runChannelBuilderTest(t, "metrics-server/secure-1.18", []string{"metrics-server.addons.k8s.io-k8s-1.11"})

View File

@ -0,0 +1,226 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
labels:
addon.kops.k8s.io/name: authentication.aws
app.kubernetes.io/managed-by: kops
role.kubernetes.io/authentication: "1"
name: iamidentitymappings.iamauthenticator.k8s.aws
spec:
group: iamauthenticator.k8s.aws
names:
categories:
- all
kind: IAMIdentityMapping
plural: iamidentitymappings
singular: iamidentitymapping
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
properties:
spec:
properties:
arn:
type: string
groups:
items:
type: string
type: array
username:
type: string
required:
- arn
- username
type: object
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
labels:
addon.kops.k8s.io/name: authentication.aws
app.kubernetes.io/managed-by: kops
role.kubernetes.io/authentication: "1"
name: aws-iam-authenticator
rules:
- apiGroups:
- iamauthenticator.k8s.aws
resources:
- iamidentitymappings
verbs:
- get
- list
- watch
- apiGroups:
- iamauthenticator.k8s.aws
resources:
- iamidentitymappings/status
verbs:
- patch
- update
- apiGroups:
- ""
resources:
- events
verbs:
- create
- update
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- list
- watch
- apiGroups:
- ""
resourceNames:
- aws-auth
resources:
- configmaps
verbs:
- get
---
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: null
labels:
addon.kops.k8s.io/name: authentication.aws
app.kubernetes.io/managed-by: kops
role.kubernetes.io/authentication: "1"
name: aws-iam-authenticator
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
creationTimestamp: null
labels:
addon.kops.k8s.io/name: authentication.aws
app.kubernetes.io/managed-by: kops
role.kubernetes.io/authentication: "1"
name: aws-iam-authenticator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: aws-iam-authenticator
subjects:
- kind: ServiceAccount
name: aws-iam-authenticator
namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
annotations:
seccomp.security.alpha.kubernetes.io/pod: runtime/default
creationTimestamp: null
labels:
addon.kops.k8s.io/name: authentication.aws
app.kubernetes.io/managed-by: kops
k8s-app: aws-iam-authenticator
role.kubernetes.io/authentication: "1"
name: aws-iam-authenticator
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: aws-iam-authenticator
template:
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
labels:
k8s-app: aws-iam-authenticator
spec:
containers:
- args:
- server
- --cluster-id=minimal.example.com
- --state-dir=/var/aws-iam-authenticator
- --kubeconfig-pregenerated=true
- --backend-mode=CRD
image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-iam-authenticator:v0.5.3-debian-stretch
livenessProbe:
httpGet:
host: 127.0.0.1
path: /healthz
port: 21362
scheme: HTTPS
name: aws-iam-authenticator
resources:
limits:
cpu: 100m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- mountPath: /var/aws-iam-authenticator/
name: state
- mountPath: /etc/kubernetes/aws-iam-authenticator/
name: output
hostNetwork: true
nodeSelector:
node-role.kubernetes.io/master: ""
priorityClassName: system-node-critical
serviceAccountName: aws-iam-authenticator
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
- effect: NoSchedule
key: node-role.kubernetes.io/api-server
- key: node.cloudprovider.kubernetes.io/uninitialized
operator: Exists
- key: CriticalAddonsOnly
operator: Exists
volumes:
- hostPath:
path: /srv/kubernetes/aws-iam-authenticator/
name: output
- hostPath:
path: /srv/kubernetes/aws-iam-authenticator/
name: state
updateStrategy:
type: RollingUpdate
---
apiVersion: iamauthenticator.k8s.aws/v1alpha1
kind: IAMIdentityMapping
metadata:
creationTimestamp: null
labels:
addon.kops.k8s.io/name: authentication.aws
app.kubernetes.io/managed-by: kops
k8s-app: aws-iam-authenticator
role.kubernetes.io/authentication: "1"
name: iam-identity-mapping-0
spec:
arn: arn:aws:iam::00000000:role/AdminRole
groups:
- system:masters
username: administrators:{{SessionName}}

View File

@ -0,0 +1,50 @@
apiVersion: kops.k8s.io/v1alpha2
kind: Cluster
metadata:
creationTimestamp: "2016-12-10T22:42:27Z"
name: minimal.example.com
spec:
addons:
- manifest: s3://somebucket/example.yaml
authentication:
aws:
backendMode: CRD
identityMappings:
- arn: arn:aws:iam::00000000:role/AdminRole
username: administrators:{{SessionName}}
groups:
- system:masters
kubernetesApiAccess:
- 0.0.0.0/0
channel: stable
cloudProvider: aws
configBase: memfs://clusters.example.com/minimal.example.com
etcdClusters:
- etcdMembers:
- instanceGroup: master-us-test-1a
name: master-us-test-1a
name: main
- etcdMembers:
- instanceGroup: master-us-test-1a
name: master-us-test-1a
name: events
iam: {}
kubernetesVersion: v1.20.0
masterInternalName: api.internal.minimal.example.com
masterPublicName: api.minimal.example.com
additionalSans:
- proxy.api.minimal.example.com
networkCIDR: 172.20.0.0/16
networking:
cni: {}
nonMasqueradeCIDR: 100.64.0.0/10
sshAccess:
- 0.0.0.0/0
topology:
masters: public
nodes: public
subnets:
- cidr: 172.20.32.0/19
name: us-test-1a
type: Public
zone: us-test-1a

View File

@ -0,0 +1,61 @@
kind: Addons
metadata:
creationTimestamp: null
name: bootstrap
spec:
addons:
- id: k8s-1.16
manifest: kops-controller.addons.k8s.io/k8s-1.16.yaml
manifestHash: 46120dbd8151e5dffad79c48273eb910ff42fa4e05f40f76a39d554d77497f6d
name: kops-controller.addons.k8s.io
needsRollingUpdate: control-plane
selector:
k8s-addon: kops-controller.addons.k8s.io
version: 9.99.0
- manifest: core.addons.k8s.io/v1.4.0.yaml
manifestHash: 18233793a8442224d052e44891e737c67ccfb4e051e95216392319653f4cb0e5
name: core.addons.k8s.io
selector:
k8s-addon: core.addons.k8s.io
version: 9.99.0
- id: k8s-1.12
manifest: coredns.addons.k8s.io/k8s-1.12.yaml
manifestHash: 88ffe1a3752cf290450cc94bd53aea49a665e411dbf4cfe9c1a2cc5b027f12ef
name: coredns.addons.k8s.io
selector:
k8s-addon: coredns.addons.k8s.io
version: 9.99.0
- id: k8s-1.9
manifest: kubelet-api.rbac.addons.k8s.io/k8s-1.9.yaml
manifestHash: 01c120e887bd98d82ef57983ad58a0b22bc85efb48108092a24c4b82e4c9ea81
name: kubelet-api.rbac.addons.k8s.io
selector:
k8s-addon: kubelet-api.rbac.addons.k8s.io
version: 9.99.0
- manifest: limit-range.addons.k8s.io/v1.5.0.yaml
manifestHash: 2d55c3bc5e354e84a3730a65b42f39aba630a59dc8d32b30859fcce3d3178bc2
name: limit-range.addons.k8s.io
selector:
k8s-addon: limit-range.addons.k8s.io
version: 9.99.0
- id: k8s-1.12
manifest: dns-controller.addons.k8s.io/k8s-1.12.yaml
manifestHash: 08d576cf7e30936c5a077d9d8439f1a7a1245e737722faa477eb734e87b292aa
name: dns-controller.addons.k8s.io
selector:
k8s-addon: dns-controller.addons.k8s.io
version: 9.99.0
- id: v1.15.0
manifest: storage-aws.addons.k8s.io/v1.15.0.yaml
manifestHash: 065ae832ddac8d0931e9992d6a76f43a33a36975a38003b34f4c5d86a7d42780
name: storage-aws.addons.k8s.io
selector:
k8s-addon: storage-aws.addons.k8s.io
version: 9.99.0
- id: k8s-1.12
manifest: authentication.aws/k8s-1.12.yaml
manifestHash: 0cfdcbd7be8aa8a99c0e23b9417bf1c0e23bdbb5a5702168ff26f9248284ce8d
name: authentication.aws
selector:
role.kubernetes.io/authentication: "1"
version: 9.99.0