Merge pull request #1268 from justinsb/api_exposure_in_topology

Control how we expose the API
This commit is contained in:
Justin Santa Barbara 2017-01-04 23:48:18 -05:00 committed by GitHub
commit ccb9350e39
32 changed files with 551 additions and 75 deletions

View File

@ -275,8 +275,11 @@ examples:
# api machinery regenerate
apimachinery:
#go install ./cmd/libs/go2idl/conversion-gen
# conversion: go install ./cmd/libs/go2idl/conversion-gen
${GOPATH}/bin/conversion-gen --skip-unsafe=true --input-dirs k8s.io/kops/pkg/apis/kops/v1alpha1 --v=8 --output-file-base=zz_generated.conversion
# defaulters: go install ./cmd/libs/go2idl/defaulter-gen
${GOPATH}/bin/defaulter-gen --input-dirs k8s.io/kops/pkg/apis/kops/v1alpha1 --v=8 --output-file-base=zz_generated.defaults
${GOPATH}/bin/defaulter-gen --input-dirs k8s.io/kops/pkg/apis/kops/v1alpha2 --v=8 --output-file-base=zz_generated.defaults
#go install github.com/ugorji/go/codec/codecgen
# codecgen works only if invoked from directory where the file is located.
#cd pkg/apis/kops/v1alpha2/ && ~/k8s/bin/codecgen -d 1234 -o types.generated.go instancegroup.go cluster.go federation.go

View File

@ -4,7 +4,34 @@ This list is not complete, but aims to document any keys that are less than self
## spec
### adminAccess
### api
This object configures how we expose the API:
* `dns` will allow direct access to master instances, and configure DNS to point directly to the master nodes.
* `loadBalancer` will configure a load balancer (ELB) in front of the master nodes, and configure DNS to point to the ELB.
DNS example:
```yaml
spec:
api:
dns: {}
```
When configuring a LoadBalancer, you can also choose to have a public ELB or an internal (VPC only) ELB. The `type`
field should be `Public` or `Internal`.
```yaml
spec:
api:
loadBalancer:
type: Public
```
### sshAccess
This array configures the CIDRs that are able to ssh into nodes. On AWS this is manifested as inbound security group rules on the `nodes` and `master` security groups.
@ -12,7 +39,19 @@ Use this key to restrict cluster access to an office ip address range, for examp
```yaml
spec:
adminAccess:
sshAccess:
- 12.34.56.78/32
```
### apiAccess
This array configures the CIDRs that are able to access the kubernetes API. On AWS this is manifested as inbound security group rules on the ELB or master security groups.
Use this key to restrict cluster access to an office ip address range, for example.
```yaml
spec:
apiAccess:
- 12.34.56.78/32
```

View File

@ -233,6 +233,33 @@ type ClusterSpec struct {
// Networking configuration
Networking *NetworkingSpec `json:"networking,omitempty"`
// API field controls how the API is exposed outside the cluster
API *AccessSpec `json:"api,omitempty"`
}
type AccessSpec struct {
DNS *DNSAccessSpec `json:"dns,omitempty"`
LoadBalancer *LoadBalancerAccessSpec `json:"loadBalancer,omitempty"`
}
func (s *AccessSpec) IsEmpty() bool {
return s.DNS == nil && s.LoadBalancer == nil
}
type DNSAccessSpec struct {
}
// LoadBalancerType string describes LoadBalancer types (public, internal)
type LoadBalancerType string
const (
LoadBalancerTypePublic LoadBalancerType = "Public"
LoadBalancerTypeInternal LoadBalancerType = "Internal"
)
type LoadBalancerAccessSpec struct {
Type LoadBalancerType `json:"type,omitempty"`
}
type KubeDNSConfig struct {
@ -370,23 +397,3 @@ func (c *Cluster) FillDefaults() error {
func (c *Cluster) SharedVPC() bool {
return c.Spec.NetworkID != ""
}
// --------------------------------------------------------------------------------------------
// Network Topology functions for template parsing
//
// Each of these functions can be used in the model templates
// The go template package currently only supports boolean
// operations, so the logic is mapped here as *Cluster functions.
//
// A function will need to be defined for all new topologies, if we plan to use them in the
// model templates.
// --------------------------------------------------------------------------------------------
func (c *Cluster) IsTopologyPrivate() bool {
return (c.Spec.Topology.Masters == TopologyPrivate && c.Spec.Topology.Nodes == TopologyPrivate)
}
func (c *Cluster) IsTopologyPublic() bool {
return (c.Spec.Topology.Masters == TopologyPublic && c.Spec.Topology.Nodes == TopologyPublic)
}
func (c *Cluster) IsTopologyPrivateMasters() bool {
return (c.Spec.Topology.Masters == TopologyPrivate && c.Spec.Topology.Nodes == TopologyPublic)
}

View File

@ -229,6 +229,33 @@ type ClusterSpec struct {
// Networking configuration
Networking *NetworkingSpec `json:"networking,omitempty"`
// API field controls how the API is exposed outside the cluster
API *AccessSpec `json:"api,omitempty"`
}
type AccessSpec struct {
DNS *DNSAccessSpec `json:"dns,omitempty"`
LoadBalancer *LoadBalancerAccessSpec `json:"loadBalancer,omitempty"`
}
func (s *AccessSpec) IsEmpty() bool {
return s.DNS == nil && s.LoadBalancer == nil
}
type DNSAccessSpec struct {
}
// LoadBalancerType string describes LoadBalancer types (public, internal)
type LoadBalancerType string
const (
LoadBalancerTypePublic LoadBalancerType = "Public"
LoadBalancerTypeInternal LoadBalancerType = "Internal"
)
type LoadBalancerAccessSpec struct {
Type LoadBalancerType `json:"type,omitempty"`
}
type KubeDNSConfig struct {

View File

@ -17,9 +17,48 @@ limitations under the License.
package v1alpha1
import (
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return nil
RegisterDefaults(scheme)
return scheme.AddDefaultingFuncs(
SetDefaults_ClusterSpec,
)
}
func SetDefaults_ClusterSpec(obj *ClusterSpec) {
if obj.Topology == nil {
obj.Topology = &TopologySpec{}
}
if obj.Topology.Masters == "" {
obj.Topology.Masters = TopologyPublic
}
if obj.Topology.Nodes == "" {
obj.Topology.Nodes = TopologyPublic
}
if obj.API == nil {
obj.API = &AccessSpec{}
}
if obj.API.IsEmpty() {
switch obj.Topology.Masters {
case TopologyPublic:
obj.API.DNS = &DNSAccessSpec{}
case TopologyPrivate:
obj.API.LoadBalancer = &LoadBalancerAccessSpec{}
default:
glog.Infof("unknown master topology type: %q", obj.Topology.Masters)
}
}
if obj.API.LoadBalancer != nil && obj.API.LoadBalancer.Type == "" {
obj.API.LoadBalancer.Type = LoadBalancerTypePublic
}
}

View File

@ -15,4 +15,5 @@ limitations under the License.
*/
// +k8s:conversion-gen=k8s.io/kops/pkg/apis/kops
// +k8s:defaulter-gen=TypeMeta
package v1alpha1

View File

@ -23,9 +23,7 @@ import (
)
var (
// TODO: Defaulting functions
//SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs)
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
//SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2016 The Kubernetes Authors.
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -34,6 +34,8 @@ func init() {
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_AccessSpec_To_kops_AccessSpec,
Convert_kops_AccessSpec_To_v1alpha1_AccessSpec,
Convert_v1alpha1_CNINetworkingSpec_To_kops_CNINetworkingSpec,
Convert_kops_CNINetworkingSpec_To_v1alpha1_CNINetworkingSpec,
Convert_v1alpha1_CalicoNetworkingSpec_To_kops_CalicoNetworkingSpec,
@ -46,6 +48,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_ClusterList_To_v1alpha1_ClusterList,
Convert_v1alpha1_ClusterSpec_To_kops_ClusterSpec,
Convert_kops_ClusterSpec_To_v1alpha1_ClusterSpec,
Convert_v1alpha1_DNSAccessSpec_To_kops_DNSAccessSpec,
Convert_kops_DNSAccessSpec_To_v1alpha1_DNSAccessSpec,
Convert_v1alpha1_DockerConfig_To_kops_DockerConfig,
Convert_kops_DockerConfig_To_v1alpha1_DockerConfig,
Convert_v1alpha1_EtcdClusterSpec_To_kops_EtcdClusterSpec,
@ -84,6 +88,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kops_KubenetNetworkingSpec_To_v1alpha1_KubenetNetworkingSpec,
Convert_v1alpha1_LeaderElectionConfiguration_To_kops_LeaderElectionConfiguration,
Convert_kops_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration,
Convert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec,
Convert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec,
Convert_v1alpha1_NetworkingSpec_To_kops_NetworkingSpec,
Convert_kops_NetworkingSpec_To_v1alpha1_NetworkingSpec,
Convert_v1alpha1_WeaveNetworkingSpec_To_kops_WeaveNetworkingSpec,
@ -91,6 +97,58 @@ func RegisterConversions(scheme *runtime.Scheme) error {
)
}
func autoConvert_v1alpha1_AccessSpec_To_kops_AccessSpec(in *AccessSpec, out *kops.AccessSpec, s conversion.Scope) error {
if in.DNS != nil {
in, out := &in.DNS, &out.DNS
*out = new(kops.DNSAccessSpec)
if err := Convert_v1alpha1_DNSAccessSpec_To_kops_DNSAccessSpec(*in, *out, s); err != nil {
return err
}
} else {
out.DNS = nil
}
if in.LoadBalancer != nil {
in, out := &in.LoadBalancer, &out.LoadBalancer
*out = new(kops.LoadBalancerAccessSpec)
if err := Convert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(*in, *out, s); err != nil {
return err
}
} else {
out.LoadBalancer = nil
}
return nil
}
func Convert_v1alpha1_AccessSpec_To_kops_AccessSpec(in *AccessSpec, out *kops.AccessSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_AccessSpec_To_kops_AccessSpec(in, out, s)
}
func autoConvert_kops_AccessSpec_To_v1alpha1_AccessSpec(in *kops.AccessSpec, out *AccessSpec, s conversion.Scope) error {
if in.DNS != nil {
in, out := &in.DNS, &out.DNS
*out = new(DNSAccessSpec)
if err := Convert_kops_DNSAccessSpec_To_v1alpha1_DNSAccessSpec(*in, *out, s); err != nil {
return err
}
} else {
out.DNS = nil
}
if in.LoadBalancer != nil {
in, out := &in.LoadBalancer, &out.LoadBalancer
*out = new(LoadBalancerAccessSpec)
if err := Convert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec(*in, *out, s); err != nil {
return err
}
} else {
out.LoadBalancer = nil
}
return nil
}
func Convert_kops_AccessSpec_To_v1alpha1_AccessSpec(in *kops.AccessSpec, out *AccessSpec, s conversion.Scope) error {
return autoConvert_kops_AccessSpec_To_v1alpha1_AccessSpec(in, out, s)
}
func autoConvert_v1alpha1_CNINetworkingSpec_To_kops_CNINetworkingSpec(in *CNINetworkingSpec, out *kops.CNINetworkingSpec, s conversion.Scope) error {
return nil
}
@ -333,6 +391,15 @@ func autoConvert_v1alpha1_ClusterSpec_To_kops_ClusterSpec(in *ClusterSpec, out *
} else {
out.Networking = nil
}
if in.API != nil {
in, out := &in.API, &out.API
*out = new(kops.AccessSpec)
if err := Convert_v1alpha1_AccessSpec_To_kops_AccessSpec(*in, *out, s); err != nil {
return err
}
} else {
out.API = nil
}
return nil
}
@ -460,9 +527,34 @@ func autoConvert_kops_ClusterSpec_To_v1alpha1_ClusterSpec(in *kops.ClusterSpec,
} else {
out.Networking = nil
}
if in.API != nil {
in, out := &in.API, &out.API
*out = new(AccessSpec)
if err := Convert_kops_AccessSpec_To_v1alpha1_AccessSpec(*in, *out, s); err != nil {
return err
}
} else {
out.API = nil
}
return nil
}
func autoConvert_v1alpha1_DNSAccessSpec_To_kops_DNSAccessSpec(in *DNSAccessSpec, out *kops.DNSAccessSpec, s conversion.Scope) error {
return nil
}
func Convert_v1alpha1_DNSAccessSpec_To_kops_DNSAccessSpec(in *DNSAccessSpec, out *kops.DNSAccessSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_DNSAccessSpec_To_kops_DNSAccessSpec(in, out, s)
}
func autoConvert_kops_DNSAccessSpec_To_v1alpha1_DNSAccessSpec(in *kops.DNSAccessSpec, out *DNSAccessSpec, s conversion.Scope) error {
return nil
}
func Convert_kops_DNSAccessSpec_To_v1alpha1_DNSAccessSpec(in *kops.DNSAccessSpec, out *DNSAccessSpec, s conversion.Scope) error {
return autoConvert_kops_DNSAccessSpec_To_v1alpha1_DNSAccessSpec(in, out, s)
}
func autoConvert_v1alpha1_DockerConfig_To_kops_DockerConfig(in *DockerConfig, out *kops.DockerConfig, s conversion.Scope) error {
out.Bridge = in.Bridge
out.LogLevel = in.LogLevel
@ -1083,6 +1175,24 @@ func Convert_kops_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfigur
return autoConvert_kops_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in, out, s)
}
func autoConvert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(in *LoadBalancerAccessSpec, out *kops.LoadBalancerAccessSpec, s conversion.Scope) error {
out.Type = kops.LoadBalancerType(in.Type)
return nil
}
func Convert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(in *LoadBalancerAccessSpec, out *kops.LoadBalancerAccessSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(in, out, s)
}
func autoConvert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec(in *kops.LoadBalancerAccessSpec, out *LoadBalancerAccessSpec, s conversion.Scope) error {
out.Type = LoadBalancerType(in.Type)
return nil
}
func Convert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec(in *kops.LoadBalancerAccessSpec, out *LoadBalancerAccessSpec, s conversion.Scope) error {
return autoConvert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec(in, out, s)
}
func autoConvert_v1alpha1_NetworkingSpec_To_kops_NetworkingSpec(in *NetworkingSpec, out *kops.NetworkingSpec, s conversion.Scope) error {
if in.Classic != nil {
in, out := &in.Classic, &out.Classic

View File

@ -0,0 +1,45 @@
// +build !ignore_autogenerated
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
package v1alpha1
import (
runtime "k8s.io/kubernetes/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&Cluster{}, func(obj interface{}) { SetObjectDefaults_Cluster(obj.(*Cluster)) })
scheme.AddTypeDefaultingFunc(&ClusterList{}, func(obj interface{}) { SetObjectDefaults_ClusterList(obj.(*ClusterList)) })
return nil
}
func SetObjectDefaults_Cluster(in *Cluster) {
SetDefaults_ClusterSpec(&in.Spec)
}
func SetObjectDefaults_ClusterList(in *ClusterList) {
for i := range in.Items {
a := &in.Items[i]
SetObjectDefaults_Cluster(a)
}
}

View File

@ -149,6 +149,33 @@ type ClusterSpec struct {
// Networking configuration
Networking *NetworkingSpec `json:"networking,omitempty"`
// API field controls how the API is exposed outside the cluster
API *AccessSpec `json:"api,omitempty"`
}
type AccessSpec struct {
DNS *DNSAccessSpec `json:"dns,omitempty"`
LoadBalancer *LoadBalancerAccessSpec `json:"loadBalancer,omitempty"`
}
func (s *AccessSpec) IsEmpty() bool {
return s.DNS == nil && s.LoadBalancer == nil
}
type DNSAccessSpec struct {
}
// LoadBalancerType string describes LoadBalancer types (public, internal)
type LoadBalancerType string
const (
LoadBalancerTypePublic LoadBalancerType = "Public"
LoadBalancerTypeInternal LoadBalancerType = "Internal"
)
type LoadBalancerAccessSpec struct {
Type LoadBalancerType `json:"type,omitempty"`
}
type KubeDNSConfig struct {

View File

@ -0,0 +1,64 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
RegisterDefaults(scheme)
return scheme.AddDefaultingFuncs(
SetDefaults_ClusterSpec,
)
}
func SetDefaults_ClusterSpec(obj *ClusterSpec) {
if obj.Topology == nil {
obj.Topology = &TopologySpec{}
}
if obj.Topology.Masters == "" {
obj.Topology.Masters = TopologyPublic
}
if obj.Topology.Nodes == "" {
obj.Topology.Nodes = TopologyPublic
}
if obj.API == nil {
obj.API = &AccessSpec{}
}
if obj.API.IsEmpty() {
switch obj.Topology.Masters {
case TopologyPublic:
obj.API.DNS = &DNSAccessSpec{}
case TopologyPrivate:
obj.API.LoadBalancer = &LoadBalancerAccessSpec{}
default:
glog.Infof("unknown master topology type: %q", obj.Topology.Masters)
}
}
if obj.API.LoadBalancer != nil && obj.API.LoadBalancer.Type == "" {
obj.API.LoadBalancer.Type = LoadBalancerTypePublic
}
}

View File

@ -14,4 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:conversion-gen=k8s.io/kops/pkg/apis/kops
// +k8s:defaulter-gen=TypeMeta
package v1alpha2 // import "k8s.io/kops/pkg/apis/kops/v1alpha2"

View File

@ -24,8 +24,7 @@ import (
var (
// TODO: Defaulting functions
//SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs)
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
//SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -0,0 +1,52 @@
// +build !ignore_autogenerated
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
package v1alpha2
import (
runtime "k8s.io/kubernetes/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&Channel{}, func(obj interface{}) { SetObjectDefaults_Channel(obj.(*Channel)) })
scheme.AddTypeDefaultingFunc(&Cluster{}, func(obj interface{}) { SetObjectDefaults_Cluster(obj.(*Cluster)) })
scheme.AddTypeDefaultingFunc(&ClusterList{}, func(obj interface{}) { SetObjectDefaults_ClusterList(obj.(*ClusterList)) })
return nil
}
func SetObjectDefaults_Channel(in *Channel) {
if in.Spec.Cluster != nil {
SetDefaults_ClusterSpec(in.Spec.Cluster)
}
}
func SetObjectDefaults_Cluster(in *Cluster) {
SetDefaults_ClusterSpec(&in.Spec)
}
func SetObjectDefaults_ClusterList(in *ClusterList) {
for i := range in.Items {
a := &in.Items[i]
SetObjectDefaults_Cluster(a)
}
}

View File

@ -31,12 +31,17 @@ type APILoadBalancerBuilder struct {
var _ fi.ModelBuilder = &APILoadBalancerBuilder{}
func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
// Configuration where an ELB fronts the master (apiservers in particular)
// Configuration where an ELB fronts the API
if !b.UseLoadBalancerForAPI() {
return nil
}
lbSpec := b.Cluster.Spec.API.LoadBalancer
if lbSpec == nil {
// Skipping API ELB creation; not requested in Spec
return nil
}
var elb *awstasks.LoadBalancer
{
elbID, err := b.GetELBName32("api")
@ -50,11 +55,12 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
switch subnet.Type {
case kops.SubnetTypePublic:
if !b.Cluster.IsTopologyPublic() {
if b.Cluster.Spec.Topology.Masters != kops.TopologyPublic {
continue
}
case kops.SubnetTypeUtility:
if !b.Cluster.IsTopologyPrivate() {
if b.Cluster.Spec.Topology.Masters != kops.TopologyPrivate {
continue
}
@ -89,6 +95,15 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
},
}
switch lbSpec.Type {
case kops.LoadBalancerTypeInternal:
elb.Scheme = s("internal")
case kops.LoadBalancerTypePublic:
elb.Scheme = nil
default:
return fmt.Errorf("unknown elb Type: %q", lbSpec.Type)
}
c.AddTask(elb)
}

View File

@ -89,14 +89,47 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
{
associatePublicIP := true
if b.Cluster.IsTopologyPublic() {
switch ig.Spec.Role {
case kops.InstanceGroupRoleMaster:
switch b.Cluster.Spec.Topology.Masters {
case kops.TopologyPrivate:
associatePublicIP = false
// TODO: what if AssociatePublicIP is set
case kops.TopologyPublic:
associatePublicIP = true
if ig.Spec.AssociatePublicIP != nil {
associatePublicIP = *ig.Spec.AssociatePublicIP
}
default:
return fmt.Errorf("unhandled master topology %q", b.Cluster.Spec.Topology.Masters)
}
case kops.InstanceGroupRoleNode:
switch b.Cluster.Spec.Topology.Nodes {
case kops.TopologyPrivate:
associatePublicIP = false
// TODO: We probably should honor AssociatePublicIP
case kops.TopologyPublic:
associatePublicIP = true
if ig.Spec.AssociatePublicIP != nil {
associatePublicIP = *ig.Spec.AssociatePublicIP
}
default:
return fmt.Errorf("unhandled master topology %q", b.Cluster.Spec.Topology.Masters)
}
case kops.InstanceGroupRoleBastion:
associatePublicIP = true
if ig.Spec.AssociatePublicIP != nil {
associatePublicIP = *ig.Spec.AssociatePublicIP
}
}
if b.Cluster.IsTopologyPrivate() {
associatePublicIP = false
default:
return fmt.Errorf("Unknown instance group role %q", ig.Spec.Role)
}
t.AssociatePublicIP = &associatePublicIP
}

View File

@ -40,10 +40,6 @@ type BastionModelBuilder struct {
var _ fi.ModelBuilder = &BastionModelBuilder{}
func (b *BastionModelBuilder) Build(c *fi.ModelBuilderContext) error {
if !b.Cluster.IsTopologyPrivate() {
return nil
}
var bastionGroups []*kops.InstanceGroup
for _, ig := range b.InstanceGroups {
if ig.Spec.Role == kops.InstanceGroupRoleBastion {

View File

@ -151,7 +151,10 @@ func (m *KopsModelContext) CloudTagsForInstanceGroup(ig *kops.InstanceGroup) (ma
}
func (m *KopsModelContext) UseLoadBalancerForAPI() bool {
return m.Cluster.Spec.Topology.Masters == kops.TopologyPrivate
if m.Cluster.Spec.API == nil {
return false
}
return m.Cluster.Spec.API.LoadBalancer != nil
}
func (m *KopsModelContext) UsePrivateDNS() bool {

View File

@ -21,7 +21,6 @@ import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
"strconv"
)
// ExternalAccessModelBuilder configures security group rules for external access
@ -42,19 +41,24 @@ func (b *ExternalAccessModelBuilder) Build(c *fi.ModelBuilderContext) error {
}
// SSH is open to AdminCIDR set
if b.Cluster.IsTopologyPublic() {
for i, sshAccess := range b.Cluster.Spec.SSHAccess {
if b.Cluster.Spec.Topology.Masters == kops.TopologyPublic {
for _, sshAccess := range b.Cluster.Spec.SSHAccess {
c.AddTask(&awstasks.SecurityGroupRule{
Name: s("ssh-external-to-master-" + strconv.Itoa(i)),
Name: s("ssh-external-to-master-" + sshAccess),
SecurityGroup: b.LinkToSecurityGroup(kops.InstanceGroupRoleMaster),
Protocol: s("tcp"),
FromPort: i64(22),
ToPort: i64(22),
CIDR: s(sshAccess),
})
}
}
// SSH is open to AdminCIDR set
if b.Cluster.Spec.Topology.Nodes == kops.TopologyPublic {
for _, sshAccess := range b.Cluster.Spec.SSHAccess {
c.AddTask(&awstasks.SecurityGroupRule{
Name: s("ssh-external-to-node-" + strconv.Itoa(i)),
Name: s("ssh-external-to-node-" + sshAccess),
SecurityGroup: b.LinkToSecurityGroup(kops.InstanceGroupRoleNode),
Protocol: s("tcp"),
FromPort: i64(22),
@ -62,15 +66,17 @@ func (b *ExternalAccessModelBuilder) Build(c *fi.ModelBuilderContext) error {
CIDR: s(sshAccess),
})
}
}
if !b.UseLoadBalancerForAPI() {
// Configuration for the master, when not using a Loadbalancer (ELB)
// We expect that either the IP address is published, or DNS is set up to point to the IPs
// We need to open security groups directly to the master nodes (instead of via the ELB)
// HTTPS to the master is allowed (for API access)
for i, apiAccess := range b.Cluster.Spec.KubernetesAPIAccess {
for _, apiAccess := range b.Cluster.Spec.KubernetesAPIAccess {
t := &awstasks.SecurityGroupRule{
Name: s("https-external-to-master-" + strconv.Itoa(i)),
Name: s("https-external-to-master-" + apiAccess),
SecurityGroup: b.LinkToSecurityGroup(kops.InstanceGroupRoleMaster),
Protocol: s("tcp"),
FromPort: i64(443),

View File

@ -4,6 +4,8 @@ metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: ha.example.com
spec:
api:
dns: {}
channel: stable
cloudProvider: aws
configBase: memfs://tests/ha.example.com

View File

@ -4,6 +4,8 @@ metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: ha.example.com
spec:
api:
dns: {}
channel: stable
cloudProvider: aws
configBase: memfs://tests/ha.example.com

View File

@ -4,6 +4,8 @@ metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: minimal.example.com
spec:
api:
dns: {}
channel: stable
cloudProvider: aws
configBase: memfs://tests/minimal.example.com

View File

@ -4,6 +4,8 @@ metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: minimal.example.com
spec:
api:
dns: {}
channel: stable
cloudProvider: aws
configBase: memfs://tests/minimal.example.com

View File

@ -4,6 +4,9 @@ metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: private.example.com
spec:
api:
loadBalancer:
type: Public
channel: stable
cloudProvider: aws
configBase: memfs://tests/private.example.com

View File

@ -4,6 +4,9 @@ metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: private.example.com
spec:
api:
loadBalancer:
type: Public
channel: stable
cloudProvider: aws
configBase: memfs://tests/private.example.com

View File

@ -232,7 +232,7 @@ resource "aws_security_group_rule" "all-node-to-node" {
protocol = "-1"
}
resource "aws_security_group_rule" "https-external-to-master-0" {
resource "aws_security_group_rule" "https-external-to-master-0-0-0-0--0" {
type = "ingress"
security_group_id = "${aws_security_group.masters-minimal-141-example-com.id}"
from_port = 443
@ -259,7 +259,7 @@ resource "aws_security_group_rule" "node-egress" {
cidr_blocks = ["0.0.0.0/0"]
}
resource "aws_security_group_rule" "ssh-external-to-master-0" {
resource "aws_security_group_rule" "ssh-external-to-master-0-0-0-0--0" {
type = "ingress"
security_group_id = "${aws_security_group.masters-minimal-141-example-com.id}"
from_port = 22
@ -268,7 +268,7 @@ resource "aws_security_group_rule" "ssh-external-to-master-0" {
cidr_blocks = ["0.0.0.0/0"]
}
resource "aws_security_group_rule" "ssh-external-to-node-0" {
resource "aws_security_group_rule" "ssh-external-to-node-0-0-0-0--0" {
type = "ingress"
security_group_id = "${aws_security_group.nodes-minimal-141-example-com.id}"
from_port = 22

View File

@ -232,7 +232,7 @@ resource "aws_security_group_rule" "all-node-to-node" {
protocol = "-1"
}
resource "aws_security_group_rule" "https-external-to-master-0" {
resource "aws_security_group_rule" "https-external-to-master-0-0-0-0--0" {
type = "ingress"
security_group_id = "${aws_security_group.masters-minimal-example-com.id}"
from_port = 443
@ -259,7 +259,7 @@ resource "aws_security_group_rule" "node-egress" {
cidr_blocks = ["0.0.0.0/0"]
}
resource "aws_security_group_rule" "ssh-external-to-master-0" {
resource "aws_security_group_rule" "ssh-external-to-master-0-0-0-0--0" {
type = "ingress"
security_group_id = "${aws_security_group.masters-minimal-example-com.id}"
from_port = 22
@ -268,7 +268,7 @@ resource "aws_security_group_rule" "ssh-external-to-master-0" {
cidr_blocks = ["0.0.0.0/0"]
}
resource "aws_security_group_rule" "ssh-external-to-node-0" {
resource "aws_security_group_rule" "ssh-external-to-node-0-0-0-0--0" {
type = "ingress"
security_group_id = "${aws_security_group.nodes-minimal-example-com.id}"
from_port = 22

View File

@ -214,7 +214,7 @@ resource "aws_launch_configuration" "bastion-privatecalico-example-com" {
key_name = "${aws_key_pair.kubernetes-privatecalico-example-com-c4a6ed9aa889b9e2c39cd663eb9c7157.id}"
iam_instance_profile = "${aws_iam_instance_profile.bastions-privatecalico-example-com.id}"
security_groups = ["${aws_security_group.bastion-privatecalico-example-com.id}"]
associate_public_ip_address = false
associate_public_ip_address = true
root_block_device = {
volume_type = "gp2"
volume_size = 20

View File

@ -214,7 +214,7 @@ resource "aws_launch_configuration" "bastion-privateweave-example-com" {
key_name = "${aws_key_pair.kubernetes-privateweave-example-com-c4a6ed9aa889b9e2c39cd663eb9c7157.id}"
iam_instance_profile = "${aws_iam_instance_profile.bastions-privateweave-example-com.id}"
security_groups = ["${aws_security_group.bastion-privateweave-example-com.id}"]
associate_public_ip_address = false
associate_public_ip_address = true
root_block_device = {
volume_type = "gp2"
volume_size = 20

View File

@ -2,10 +2,9 @@ apiVersion: v1
kind: Pod
metadata:
annotations:
{{ if IsTopologyPublic }}
dns.alpha.kubernetes.io/external: {{ .MasterPublicName }}
{{ range $k, $v := BuildAPIServerAnnotations }}
{{ $k }}: {{ $v }}
{{ end }}
dns.alpha.kubernetes.io/internal: {{ .MasterInternalName }}
name: kube-apiserver
namespace: kube-system
labels:

View File

@ -94,9 +94,6 @@ func (tf *TemplateFunctions) AddTo(dest template.FuncMap) {
dest["Arch"] = func() string { return "amd64" }
// Network topology definitions
dest["IsTopologyPublic"] = tf.IsTopologyPublic
dest["IsTopologyPrivate"] = tf.IsTopologyPrivate
dest["IsTopologyPrivateMasters"] = tf.IsTopologyPrivateMasters
dest["GetELBName32"] = tf.modelContext.GetELBName32
dest["WellKnownServiceIP"] = tf.WellKnownServiceIP
@ -140,14 +137,6 @@ func (tf *TemplateFunctions) SharedVPC() bool {
return tf.cluster.SharedVPC()
}
// These are the network topology functions. They are boolean logic for checking which type of
// topology this cluster is set to be deployed with.
func (tf *TemplateFunctions) IsTopologyPrivate() bool { return tf.cluster.IsTopologyPrivate() }
func (tf *TemplateFunctions) IsTopologyPublic() bool { return tf.cluster.IsTopologyPublic() }
func (tf *TemplateFunctions) IsTopologyPrivateMasters() bool {
return tf.cluster.IsTopologyPrivateMasters()
}
// Image returns the docker image name for the specified component
func (tf *TemplateFunctions) Image(component string) (string, error) {
if component == "kube-dns" {

View File

@ -116,9 +116,6 @@ func newTemplateFunctions(nodeupConfig *NodeUpConfig, cluster *api.Cluster, inst
func (t *templateFunctions) populate(dest template.FuncMap) {
dest["Arch"] = func() string { return runtime.GOARCH }
dest["IsTopologyPublic"] = t.cluster.IsTopologyPublic
dest["IsTopologyPrivate"] = t.cluster.IsTopologyPrivate
dest["CACertificatePool"] = t.CACertificatePool
dest["CACertificate"] = t.CACertificate
dest["PrivateKey"] = t.PrivateKey
@ -159,6 +156,8 @@ func (t *templateFunctions) populate(dest template.FuncMap) {
dest["ProtokubeImagePullCommand"] = t.ProtokubeImagePullCommand
dest["ProtokubeFlags"] = t.ProtokubeFlags
dest["BuildAPIServerAnnotations"] = t.BuildAPIServerAnnotations
}
// IsMaster returns true if we are tagged as a master
@ -313,3 +312,12 @@ func (t *templateFunctions) KubeProxyConfig() *api.KubeProxyConfig {
return config
}
func (t *templateFunctions) BuildAPIServerAnnotations() map[string]string {
annotations := make(map[string]string)
annotations["dns.alpha.kubernetes.io/internal"] = t.cluster.Spec.MasterInternalName
if t.cluster.Spec.API != nil && t.cluster.Spec.API.DNS != nil {
annotations["dns.alpha.kubernetes.io/external"] = t.cluster.Spec.MasterPublicName
}
return annotations
}