From cf367a7ed8103af3ee715e80b89870edb97f3cad Mon Sep 17 00:00:00 2001 From: bjuncosa Date: Thu, 16 Mar 2017 12:39:40 +0100 Subject: [PATCH] Add feature: Custom IAM Roles This way Cluster IAM roles can be managed externally, either manually, using cloudformation or any other tool. --- cmd/kops/create_cluster_integration_test.go | 18 ++- docs/iam_roles.md | 30 +++- pkg/apis/kops/cluster.go | 13 ++ pkg/apis/kops/v1alpha1/cluster.go | 12 ++ .../kops/v1alpha1/zz_generated.conversion.go | 40 ++++++ pkg/apis/kops/v1alpha2/cluster.go | 12 ++ .../kops/v1alpha2/zz_generated.conversion.go | 40 ++++++ pkg/featureflag/featureflag.go | 3 + pkg/model/iam.go | 130 +++++++++++++----- .../custom_iam_role/expected-v1alpha1.yaml | 75 ++++++++++ .../custom_iam_role/expected-v1alpha2.yaml | 79 +++++++++++ .../custom_iam_role/options.yaml | 7 + 12 files changed, 419 insertions(+), 40 deletions(-) create mode 100644 tests/integration/create_cluster/custom_iam_role/expected-v1alpha1.yaml create mode 100644 tests/integration/create_cluster/custom_iam_role/expected-v1alpha2.yaml create mode 100644 tests/integration/create_cluster/custom_iam_role/options.yaml diff --git a/cmd/kops/create_cluster_integration_test.go b/cmd/kops/create_cluster_integration_test.go index 2df1dc081e87c..d5917321de574 100644 --- a/cmd/kops/create_cluster_integration_test.go +++ b/cmd/kops/create_cluster_integration_test.go @@ -18,16 +18,17 @@ package main import ( "bytes" - "github.com/golang/glog" "io/ioutil" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kops/cmd/kops/util" - "k8s.io/kops/pkg/apis/kops" - "k8s.io/kops/pkg/diff" "path" "strings" "testing" "time" + + "github.com/golang/glog" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kops/cmd/kops/util" + "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/diff" ) var MagicTimestamp = metav1.Time{Time: time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC)} @@ -38,6 +39,13 @@ func TestCreateClusterMinimal(t *testing.T) { runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/minimal", "v1alpha2") } +// TODO: https://github.com/kubernetes/kops/issues/2438 +// TestCreateClusterCustomIamRole runs kops create cluster custom_iam_role.example.com --zones us-test-1a +// func TestCreateClusterCustomIamRole(t *testing.T) { +// runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/custom_iam_role", "v1alpha1") +// runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/custom_iam_role", "v1alpha2") +// } + // TestCreateClusterHA runs kops create cluster ha.example.com --zones us-test-1a,us-test-1b,us-test-1c --master-zones us-test-1a,us-test-1b,us-test-1c func TestCreateClusterHA(t *testing.T) { runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/ha", "v1alpha1") diff --git a/docs/iam_roles.md b/docs/iam_roles.md index bb2a0c4842346..40d909edafc1b 100644 --- a/docs/iam_roles.md +++ b/docs/iam_roles.md @@ -2,9 +2,9 @@ Two IAM roles are created for the cluster: one for the masters, and one for the nodes. -> Work is being done on scoping permissions to the minimum required to setup and maintain cluster. +> Work is being done on scoping permissions to the minimum required to setup and maintain cluster. > Please note that currently all Pods running on your cluster have access to instance IAM role. -> Consider using projects such as [kube2iam](https://github.com/jtblin/kube2iam) to prevent that. +> Consider using projects such as [kube2iam](https://github.com/jtblin/kube2iam) to prevent that. Master permissions: @@ -136,3 +136,29 @@ You can have an additional policy for each kops role (node, master, bastion). Fo } ] ``` + +## Reusing Existing Policies + +Sometimes you may need to reuse existing IAM roles. You can do this +through the `customPolicies` cluster spec API field. This setting is highly advanced +and only enabled via CustomPoliciesSupport feature flag. Setting the wrong role +permissions can impact various components inside of Kubernetes, and cause +unexpected issues. This feature is in place to support the initial documenting and testing the creation of custom roles. Again, use the existing kops functionality, or reach out +if you want to help! + +At this point, we do not have a full definition of the fine grain roles. Please refer +[to](https://github.com/kubernetes/kops/issues/1873) for more information. + +Please use this feature wisely! Enable the feature flag by: + +```console +$ export KOPS_FEATURE_FLAGS="+CustomPoliciesSupport" +``` +Inside the cluster spec define one or two roles specific to the master and +a node. + +```yaml + customPolicies: + node: "arn:aws:iam::123456789012:role/kops-node" + master: "arn:aws:iam::123456789012:role/kops-master" +``` diff --git a/pkg/apis/kops/cluster.go b/pkg/apis/kops/cluster.go index eea7a2199b56e..31343e8fb8b27 100644 --- a/pkg/apis/kops/cluster.go +++ b/pkg/apis/kops/cluster.go @@ -132,7 +132,13 @@ type ClusterSpec struct { // missing: default policy (currently OS security upgrades that do not require a reboot) UpdatePolicy *string `json:"updatePolicy,omitempty"` + // Use an existing custom cloud security policy for the instances. One example is to specify the name + // of an AWS IAM role for the master and another for the nodes. + // Map is keyed by: master, node + AuthPolicySpec *AuthPolicySpec `json:"authorizationSpec,omitempty"` + // Additional policies to add for roles + // Map is keyed by: master, node AdditionalPolicies *map[string]string `json:"additionalPolicies,omitempty"` //HairpinMode string `json:",omitempty"` @@ -306,6 +312,13 @@ type KubeDNSConfig struct { ServerIP string `json:"serverIP,omitempty"` } +type AuthPolicySpec struct { + // Name is the name of the policy to use for the master + Master *string `json:"master,omitempty"` + // Name is the name of the policy to use for the node + Node *string `json:"node,omitempty"` +} + type EtcdClusterSpec struct { // Name is the name of the etcd cluster (main, events etc) Name string `json:"name,omitempty"` diff --git a/pkg/apis/kops/v1alpha1/cluster.go b/pkg/apis/kops/v1alpha1/cluster.go index 3fadf474a7c48..ddc5dbe813b59 100644 --- a/pkg/apis/kops/v1alpha1/cluster.go +++ b/pkg/apis/kops/v1alpha1/cluster.go @@ -129,6 +129,11 @@ type ClusterSpec struct { // missing: default policy (currently OS security upgrades that do not require a reboot) UpdatePolicy *string `json:"updatePolicy,omitempty"` + // Use an existing custom cloud security policy for the instances. One example is to specify the name + // of an AWS IAM role for the master and another for the nodes. + // Map is keyed by: master, node + AuthPolicySpec *AuthPolicySpec `json:"authorizationSpec,omitempty"` + // Additional policies to add for roles AdditionalPolicies *map[string]string `json:"additionalPolicies,omitempty"` @@ -308,6 +313,13 @@ type KubeDNSConfig struct { // MachineType string `json:",omitempty"` //} +type AuthPolicySpec struct { + // Name is the name of the policy to use for the master + Master *string `json:"master,omitempty"` + // Name is the name of the policy to use for the node + Node *string `json:"node,omitempty"` +} + type EtcdClusterSpec struct { // Name is the name of the etcd cluster (main, events etc) Name string `json:"name,omitempty"` diff --git a/pkg/apis/kops/v1alpha1/zz_generated.conversion.go b/pkg/apis/kops/v1alpha1/zz_generated.conversion.go index e8cdb3a3de864..896454931381f 100644 --- a/pkg/apis/kops/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha1/zz_generated.conversion.go @@ -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_AuthPolicySpec_To_kops_AuthPolicySpec, + Convert_kops_AuthPolicySpec_To_v1alpha1_AuthPolicySpec, Convert_v1alpha1_AuthorizationSpec_To_kops_AuthorizationSpec, Convert_kops_AuthorizationSpec_To_v1alpha1_AuthorizationSpec, Convert_v1alpha1_CNINetworkingSpec_To_kops_CNINetworkingSpec, @@ -184,6 +186,26 @@ func Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizat return autoConvert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha1_AlwaysAllowAuthorizationSpec(in, out, s) } +func autoConvert_v1alpha1_AuthPolicySpec_To_kops_AuthPolicySpec(in *AuthPolicySpec, out *kops.AuthPolicySpec, s conversion.Scope) error { + out.Master = in.Master + out.Node = in.Node + return nil +} + +func Convert_v1alpha1_AuthPolicySpec_To_kops_AuthPolicySpec(in *AuthPolicySpec, out *kops.AuthPolicySpec, s conversion.Scope) error { + return autoConvert_v1alpha1_AuthPolicySpec_To_kops_AuthPolicySpec(in, out, s) +} + +func autoConvert_kops_AuthPolicySpec_To_v1alpha1_AuthPolicySpec(in *kops.AuthPolicySpec, out *AuthPolicySpec, s conversion.Scope) error { + out.Master = in.Master + out.Node = in.Node + return nil +} + +func Convert_kops_AuthPolicySpec_To_v1alpha1_AuthPolicySpec(in *kops.AuthPolicySpec, out *AuthPolicySpec, s conversion.Scope) error { + return autoConvert_kops_AuthPolicySpec_To_v1alpha1_AuthPolicySpec(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 @@ -435,6 +457,15 @@ func autoConvert_v1alpha1_ClusterSpec_To_kops_ClusterSpec(in *ClusterSpec, out * // WARNING: in.AdminAccess requires manual conversion: does not exist in peer-type out.IsolateMasters = in.IsolateMasters out.UpdatePolicy = in.UpdatePolicy + if in.AuthPolicySpec != nil { + in, out := &in.AuthPolicySpec, &out.AuthPolicySpec + *out = new(kops.AuthPolicySpec) + if err := Convert_v1alpha1_AuthPolicySpec_To_kops_AuthPolicySpec(*in, *out, s); err != nil { + return err + } + } else { + out.AuthPolicySpec = nil + } out.AdditionalPolicies = in.AdditionalPolicies if in.EtcdClusters != nil { in, out := &in.EtcdClusters, &out.EtcdClusters @@ -602,6 +633,15 @@ func autoConvert_kops_ClusterSpec_To_v1alpha1_ClusterSpec(in *kops.ClusterSpec, // WARNING: in.KubernetesAPIAccess requires manual conversion: does not exist in peer-type out.IsolateMasters = in.IsolateMasters out.UpdatePolicy = in.UpdatePolicy + if in.AuthPolicySpec != nil { + in, out := &in.AuthPolicySpec, &out.AuthPolicySpec + *out = new(AuthPolicySpec) + if err := Convert_kops_AuthPolicySpec_To_v1alpha1_AuthPolicySpec(*in, *out, s); err != nil { + return err + } + } else { + out.AuthPolicySpec = nil + } out.AdditionalPolicies = in.AdditionalPolicies if in.EtcdClusters != nil { in, out := &in.EtcdClusters, &out.EtcdClusters diff --git a/pkg/apis/kops/v1alpha2/cluster.go b/pkg/apis/kops/v1alpha2/cluster.go index b497b70cbb597..ecf48ffd7011d 100644 --- a/pkg/apis/kops/v1alpha2/cluster.go +++ b/pkg/apis/kops/v1alpha2/cluster.go @@ -133,6 +133,11 @@ type ClusterSpec struct { // missing: default policy (currently OS security upgrades that do not require a reboot) UpdatePolicy *string `json:"updatePolicy,omitempty"` + // Use an existing custom cloud security policy for the instances. One example is to specify the name + // of an AWS IAM role for the master and another for the nodes. + // Map is keyed by: master, node + AuthPolicySpec *AuthPolicySpec `json:"authorizationSpec,omitempty"` + // Additional policies to add for roles AdditionalPolicies *map[string]string `json:"additionalPolicies,omitempty"` @@ -268,3 +273,10 @@ type ClusterSubnetSpec struct { Type SubnetType `json:"type,omitempty"` } + +type AuthPolicySpec struct { + // Name is the name of the policy to use for the master + Master *string `json:"master,omitempty"` + // Name is the name of the policy to use for the node + Node *string `json:"node,omitempty"` +} diff --git a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go index 3680ecf806e83..fe25ab1fea3ff 100644 --- a/pkg/apis/kops/v1alpha2/zz_generated.conversion.go +++ b/pkg/apis/kops/v1alpha2/zz_generated.conversion.go @@ -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_AuthPolicySpec_To_kops_AuthPolicySpec, + Convert_kops_AuthPolicySpec_To_v1alpha2_AuthPolicySpec, Convert_v1alpha2_AuthorizationSpec_To_kops_AuthorizationSpec, Convert_kops_AuthorizationSpec_To_v1alpha2_AuthorizationSpec, Convert_v1alpha2_BastionSpec_To_kops_BastionSpec, @@ -190,6 +192,26 @@ func Convert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizat return autoConvert_kops_AlwaysAllowAuthorizationSpec_To_v1alpha2_AlwaysAllowAuthorizationSpec(in, out, s) } +func autoConvert_v1alpha2_AuthPolicySpec_To_kops_AuthPolicySpec(in *AuthPolicySpec, out *kops.AuthPolicySpec, s conversion.Scope) error { + out.Master = in.Master + out.Node = in.Node + return nil +} + +func Convert_v1alpha2_AuthPolicySpec_To_kops_AuthPolicySpec(in *AuthPolicySpec, out *kops.AuthPolicySpec, s conversion.Scope) error { + return autoConvert_v1alpha2_AuthPolicySpec_To_kops_AuthPolicySpec(in, out, s) +} + +func autoConvert_kops_AuthPolicySpec_To_v1alpha2_AuthPolicySpec(in *kops.AuthPolicySpec, out *AuthPolicySpec, s conversion.Scope) error { + out.Master = in.Master + out.Node = in.Node + return nil +} + +func Convert_kops_AuthPolicySpec_To_v1alpha2_AuthPolicySpec(in *kops.AuthPolicySpec, out *AuthPolicySpec, s conversion.Scope) error { + return autoConvert_kops_AuthPolicySpec_To_v1alpha2_AuthPolicySpec(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 @@ -471,6 +493,15 @@ func autoConvert_v1alpha2_ClusterSpec_To_kops_ClusterSpec(in *ClusterSpec, out * out.KubernetesAPIAccess = in.KubernetesAPIAccess out.IsolateMasters = in.IsolateMasters out.UpdatePolicy = in.UpdatePolicy + if in.AuthPolicySpec != nil { + in, out := &in.AuthPolicySpec, &out.AuthPolicySpec + *out = new(kops.AuthPolicySpec) + if err := Convert_v1alpha2_AuthPolicySpec_To_kops_AuthPolicySpec(*in, *out, s); err != nil { + return err + } + } else { + out.AuthPolicySpec = nil + } out.AdditionalPolicies = in.AdditionalPolicies if in.EtcdClusters != nil { in, out := &in.EtcdClusters, &out.EtcdClusters @@ -652,6 +683,15 @@ func autoConvert_kops_ClusterSpec_To_v1alpha2_ClusterSpec(in *kops.ClusterSpec, out.KubernetesAPIAccess = in.KubernetesAPIAccess out.IsolateMasters = in.IsolateMasters out.UpdatePolicy = in.UpdatePolicy + if in.AuthPolicySpec != nil { + in, out := &in.AuthPolicySpec, &out.AuthPolicySpec + *out = new(AuthPolicySpec) + if err := Convert_kops_AuthPolicySpec_To_v1alpha2_AuthPolicySpec(*in, *out, s); err != nil { + return err + } + } else { + out.AuthPolicySpec = nil + } out.AdditionalPolicies = in.AdditionalPolicies if in.EtcdClusters != nil { in, out := &in.EtcdClusters, &out.EtcdClusters diff --git a/pkg/featureflag/featureflag.go b/pkg/featureflag/featureflag.go index 81b8af0f9507b..a6a0c19f2d1d9 100644 --- a/pkg/featureflag/featureflag.go +++ b/pkg/featureflag/featureflag.go @@ -52,6 +52,9 @@ var VSphereCloudProvider = New("VSphereCloudProvider", Bool(false)) var EnableExternalDNS = New("EnableExternalDNS", Bool(false)) +// CustomPoliciesSupport if set will allow for the setting of Custom Security Policies for Node and Master. +var CustomPoliciesSupport = New("CustomPoliciesSupport", Bool(false)) + var flags = make(map[string]*FeatureFlag) var flagsMutex sync.Mutex diff --git a/pkg/model/iam.go b/pkg/model/iam.go index 69f90e0ff5a3f..316ad1b64b6b5 100644 --- a/pkg/model/iam.go +++ b/pkg/model/iam.go @@ -19,14 +19,17 @@ package model import ( "encoding/json" "fmt" + "reflect" + "strings" + "text/template" + "github.com/golang/glog" + "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/featureflag" "k8s.io/kops/pkg/model/iam" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/cloudup/awstasks" - "reflect" - "strings" - "text/template" ) // IAMModelBuilder configures IAM objects @@ -48,6 +51,7 @@ const RolePolicyTemplate = `{ }` func (b *IAMModelBuilder) Build(c *fi.ModelBuilderContext) error { + // Collect the roles in use var roles []kops.InstanceGroupRole for _, ig := range b.InstanceGroups { @@ -67,47 +71,107 @@ func (b *IAMModelBuilder) Build(c *fi.ModelBuilderContext) error { name := b.IAMName(role) var iamRole *awstasks.IAMRole - { - rolePolicy, err := b.buildAWSIAMRolePolicy() - if err != nil { - return err - } - iamRole = &awstasks.IAMRole{ - Name: s(name), - RolePolicyDocument: fi.WrapResource(rolePolicy), - ExportWithID: s(strings.ToLower(string(role)) + "s"), + arn := "" + + // Want to use a FeatureFlag in front of this to allow the validation to harden + // TODO remove the 'Spec' out of AuthPolicySpec + if b.Cluster.Spec.AuthPolicySpec != nil && featureflag.CustomPoliciesSupport.Enabled() { + + roleAsString := string(role) + + // TODO validate the role + if role == kops.InstanceGroupRoleMaster && b.Cluster.Spec.AuthPolicySpec.Master != nil { + arn = *b.Cluster.Spec.AuthPolicySpec.Master + glog.Warningf("Custom Policy Support is enabled, kops will use %s, for %s role, this is an advanced feature please use with great care", arn, roleAsString) + } else if role == kops.InstanceGroupRoleNode && b.Cluster.Spec.AuthPolicySpec.Node != nil { + arn = *b.Cluster.Spec.AuthPolicySpec.Node + glog.Warningf("Custom Policy Support is enabled, kops will use %s, for %s role, this is an advanced feature please use with great care", arn, roleAsString) } - c.AddTask(iamRole) } - { - iamPolicy := &iam.IAMPolicyResource{ - Builder: &iam.IAMPolicyBuilder{ - Cluster: b.Cluster, - Role: role, - Region: b.Region, - }, + // If we've specified an IAMRoleArn for this cluster role, + // do not create a new one + if arn != "" { + { + + // TODO validate the String values in API validation code + // format is arn:aws:iam::123456789012:role/S3Access + + rs := strings.Split(arn, "/") + + length := len(rs) + + if length != 2 { + return fmt.Errorf("unable to parse role arn %q", arn) + } + + roleName := rs[length-1] + iamRole = &awstasks.IAMRole{ + Name: &roleName, + ID: &arn, + + // We set Policy Document to nil as this role will be managed externally + RolePolicyDocument: nil, + } + + // TODO Validate role against role that kops generates + // TODO Where is out entry point to validate the role + // TODO We need to run the aws finder and we do not have access + // TODO to the cloud context here, so we need to validate somewhere else. + + // Steps + // 1. get the role + // 2. generate the role out of iam_builder + // 3. diff the two + + c.AddTask(iamRole) } + } else { - // This is slightly tricky; we need to know the hosted zone id, - // but we might be creating the hosted zone dynamically. + { + rolePolicy, err := b.buildAWSIAMRolePolicy() + if err != nil { + return err + } + + iamRole = &awstasks.IAMRole{ + Name: s(name), + RolePolicyDocument: fi.WrapResource(rolePolicy), + ExportWithID: s(strings.ToLower(string(role)) + "s"), + } + c.AddTask(iamRole) - // TODO: I don't love this technique for finding the task by name & modifying it - dnsZoneTask, found := c.Tasks["DNSZone/"+b.NameForDNSZone()] - if found { - iamPolicy.DNSZone = dnsZoneTask.(*awstasks.DNSZone) - } else { - glog.V(2).Infof("Task %q not found; won't set route53 permissions in IAM", "DNSZone/"+b.NameForDNSZone()) } - t := &awstasks.IAMRolePolicy{ - Name: s(name), - Role: iamRole, - PolicyDocument: iamPolicy, + { + iamPolicy := &iam.IAMPolicyResource{ + Builder: &iam.IAMPolicyBuilder{ + Cluster: b.Cluster, + Role: role, + Region: b.Region, + }, + } + + // This is slightly tricky; we need to know the hosted zone id, + // but we might be creating the hosted zone dynamically. + + // TODO: I don't love this technique for finding the task by name & modifying it + dnsZoneTask, found := c.Tasks["DNSZone/"+b.NameForDNSZone()] + if found { + iamPolicy.DNSZone = dnsZoneTask.(*awstasks.DNSZone) + } else { + glog.V(2).Infof("Task %q not found; won't set route53 permissions in IAM", "DNSZone/"+b.NameForDNSZone()) + } + + t := &awstasks.IAMRolePolicy{ + Name: s(name), + Role: iamRole, + PolicyDocument: iamPolicy, + } + c.AddTask(t) } - c.AddTask(t) } var iamInstanceProfile *awstasks.IAMInstanceProfile diff --git a/tests/integration/create_cluster/custom_iam_role/expected-v1alpha1.yaml b/tests/integration/create_cluster/custom_iam_role/expected-v1alpha1.yaml new file mode 100644 index 0000000000000..e36bdc9f47557 --- /dev/null +++ b/tests/integration/create_cluster/custom_iam_role/expected-v1alpha1.yaml @@ -0,0 +1,75 @@ +apiVersion: kops/v1alpha1 +kind: Cluster +metadata: + creationTimestamp: 2017-01-01T00:00:00Z + name: custom-iam-role.example.com +spec: + adminAccess: + - 0.0.0.0/0 + api: + dns: {} + channel: stable + cloudProvider: aws + configBase: memfs://tests/custom-iam-role.example.com + etcdClusters: + - etcdMembers: + - name: a + zone: us-test-1a + name: main + - etcdMembers: + - name: a + zone: us-test-1a + name: events + kubernetesVersion: v1.4.8 + masterPublicName: api.custom-iam-role.example.com + networkCIDR: 172.20.0.0/16 + networking: + kubenet: {} + nonMasqueradeCIDR: 100.64.0.0/10 + roleCustomIamRoles: + Master: foo + Node: bar + topology: + dns: + type: Public + masters: public + nodes: public + zones: + - cidr: 172.20.32.0/19 + name: us-test-1a + +--- + +apiVersion: kops/v1alpha1 +kind: InstanceGroup +metadata: + creationTimestamp: 2017-01-01T00:00:00Z + labels: + kops.k8s.io/cluster: custom-iam-role.example.com + name: master-us-test-1a +spec: + image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 + machineType: m3.medium + maxSize: 1 + minSize: 1 + role: Master + zones: + - us-test-1a + +--- + +apiVersion: kops/v1alpha1 +kind: InstanceGroup +metadata: + creationTimestamp: 2017-01-01T00:00:00Z + labels: + kops.k8s.io/cluster: custom-iam-role.example.com + name: nodes +spec: + image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 + machineType: t2.medium + maxSize: 2 + minSize: 2 + role: Node + zones: + - us-test-1a diff --git a/tests/integration/create_cluster/custom_iam_role/expected-v1alpha2.yaml b/tests/integration/create_cluster/custom_iam_role/expected-v1alpha2.yaml new file mode 100644 index 0000000000000..51fa98be4eedf --- /dev/null +++ b/tests/integration/create_cluster/custom_iam_role/expected-v1alpha2.yaml @@ -0,0 +1,79 @@ +apiVersion: kops/v1alpha2 +kind: Cluster +metadata: + creationTimestamp: 2017-01-01T00:00:00Z + name: custom-iam-role.example.com +spec: + api: + dns: {} + channel: stable + cloudProvider: aws + configBase: memfs://tests/custom-iam-role.example.com + etcdClusters: + - etcdMembers: + - instanceGroup: master-us-test-1a + name: a + name: main + - etcdMembers: + - instanceGroup: master-us-test-1a + name: a + name: events + kubernetesApiAccess: + - 0.0.0.0/0 + kubernetesVersion: v1.4.8 + masterPublicName: api.custom-iam-role.example.com + networkCIDR: 172.20.0.0/16 + networking: + kubenet: {} + nonMasqueradeCIDR: 100.64.0.0/10 + roleCustomIamRoles: + Master: foo + Node: bar + sshAccess: + - 0.0.0.0/0 + subnets: + - cidr: 172.20.32.0/19 + name: us-test-1a + type: Public + zone: us-test-1a + topology: + dns: + type: Public + masters: public + nodes: public + +--- + +apiVersion: kops/v1alpha2 +kind: InstanceGroup +metadata: + creationTimestamp: 2017-01-01T00:00:00Z + labels: + kops.k8s.io/cluster: custom-iam-role.example.com + name: master-us-test-1a +spec: + image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 + machineType: m3.medium + maxSize: 1 + minSize: 1 + role: Master + subnets: + - us-test-1a + +--- + +apiVersion: kops/v1alpha2 +kind: InstanceGroup +metadata: + creationTimestamp: 2017-01-01T00:00:00Z + labels: + kops.k8s.io/cluster: custom-iam-role.example.com + name: nodes +spec: + image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 + machineType: t2.medium + maxSize: 2 + minSize: 2 + role: Node + subnets: + - us-test-1a diff --git a/tests/integration/create_cluster/custom_iam_role/options.yaml b/tests/integration/create_cluster/custom_iam_role/options.yaml new file mode 100644 index 0000000000000..4afac6baa6825 --- /dev/null +++ b/tests/integration/create_cluster/custom_iam_role/options.yaml @@ -0,0 +1,7 @@ +ClusterName: custom-iam-role.example.com +Zones: +- us-test-1a +Cloud: aws +KubernetesVersion: v1.4.8 +MasterIAMRole: foo +NodeIAMRole: bar