mirror of https://github.com/kubernetes/kops.git
Merge pull request #5414 from Raffo/master
[WIP] Initial implementation of ACM certificate for API server ELB
This commit is contained in:
commit
54cbe492cb
|
@ -123,6 +123,9 @@ type CreateClusterOptions struct {
|
||||||
// Specify API loadbalancer as public or internal
|
// Specify API loadbalancer as public or internal
|
||||||
APILoadBalancerType string
|
APILoadBalancerType string
|
||||||
|
|
||||||
|
// Specify the SSL certificate to use for the API loadbalancer. Currently only supported in AWS.
|
||||||
|
APISSLCertificate string
|
||||||
|
|
||||||
// Allow custom public master name
|
// Allow custom public master name
|
||||||
MasterPublicName string
|
MasterPublicName string
|
||||||
|
|
||||||
|
@ -329,6 +332,7 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
|
||||||
cmd.Flags().StringVar(&options.NodeTenancy, "node-tenancy", options.NodeTenancy, "The tenancy of the node group on AWS. Can be either default or dedicated.")
|
cmd.Flags().StringVar(&options.NodeTenancy, "node-tenancy", options.NodeTenancy, "The tenancy of the node group on AWS. Can be either default or dedicated.")
|
||||||
|
|
||||||
cmd.Flags().StringVar(&options.APILoadBalancerType, "api-loadbalancer-type", options.APILoadBalancerType, "Sets the API loadbalancer type to either 'public' or 'internal'")
|
cmd.Flags().StringVar(&options.APILoadBalancerType, "api-loadbalancer-type", options.APILoadBalancerType, "Sets the API loadbalancer type to either 'public' or 'internal'")
|
||||||
|
cmd.Flags().StringVar(&options.APISSLCertificate, "api-ssl-certificate", options.APISSLCertificate, "Currently only supported in AWS. Sets the ARN of the SSL Certificate to use for the API server loadbalancer.")
|
||||||
|
|
||||||
// Allow custom public master name
|
// Allow custom public master name
|
||||||
cmd.Flags().StringVar(&options.MasterPublicName, "master-public-name", options.MasterPublicName, "Sets the public master public name")
|
cmd.Flags().StringVar(&options.MasterPublicName, "master-public-name", options.MasterPublicName, "Sets the public master public name")
|
||||||
|
@ -1054,6 +1058,10 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.APISSLCertificate != "" {
|
||||||
|
cluster.Spec.API.LoadBalancer.SSLCertificate = c.APISSLCertificate
|
||||||
|
}
|
||||||
|
|
||||||
// Use Strict IAM policy and allow AWS ECR by default when creating a new cluster
|
// Use Strict IAM policy and allow AWS ECR by default when creating a new cluster
|
||||||
cluster.Spec.IAM = &api.IAMSpec{
|
cluster.Spec.IAM = &api.IAMSpec{
|
||||||
AllowContainerRegistry: true,
|
AllowContainerRegistry: true,
|
||||||
|
|
|
@ -66,6 +66,7 @@ kops create cluster [flags]
|
||||||
```
|
```
|
||||||
--admin-access strings Restrict API access to this CIDR. If not set, access will not be restricted by IP. (default [0.0.0.0/0])
|
--admin-access strings Restrict API access to this CIDR. If not set, access will not be restricted by IP. (default [0.0.0.0/0])
|
||||||
--api-loadbalancer-type string Sets the API loadbalancer type to either 'public' or 'internal'
|
--api-loadbalancer-type string Sets the API loadbalancer type to either 'public' or 'internal'
|
||||||
|
--api-ssl-certificate string Currently only supported in AWS. Sets the ARN of the SSL Certificate to use for the API server loadbalancer.
|
||||||
--associate-public-ip Specify --associate-public-ip=[true|false] to enable/disable association of public IP for master ASG and nodes. Default is 'true'.
|
--associate-public-ip Specify --associate-public-ip=[true|false] to enable/disable association of public IP for master ASG and nodes. Default is 'true'.
|
||||||
--authorization string Authorization mode to use: AlwaysAllow or RBAC (default "RBAC")
|
--authorization string Authorization mode to use: AlwaysAllow or RBAC (default "RBAC")
|
||||||
--bastion Pass the --bastion flag to enable a bastion instance group. Only applies to private topology.
|
--bastion Pass the --bastion flag to enable a bastion instance group. Only applies to private topology.
|
||||||
|
|
|
@ -312,6 +312,7 @@ type LoadBalancerAccessSpec struct {
|
||||||
Type LoadBalancerType `json:"type,omitempty"`
|
Type LoadBalancerType `json:"type,omitempty"`
|
||||||
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
||||||
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
|
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
|
||||||
|
SSLCertificate string `json:"sslCertificate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeDNSConfig defines the kube dns configuration
|
// KubeDNSConfig defines the kube dns configuration
|
||||||
|
|
|
@ -311,6 +311,7 @@ type LoadBalancerAccessSpec struct {
|
||||||
Type LoadBalancerType `json:"type,omitempty"`
|
Type LoadBalancerType `json:"type,omitempty"`
|
||||||
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
||||||
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
|
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
|
||||||
|
SSLCertificate string `json:"sslCertificate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeDNSConfig defines the kube dns configuration
|
// KubeDNSConfig defines the kube dns configuration
|
||||||
|
|
|
@ -2679,6 +2679,7 @@ func autoConvert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(
|
||||||
out.Type = kops.LoadBalancerType(in.Type)
|
out.Type = kops.LoadBalancerType(in.Type)
|
||||||
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
||||||
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
||||||
|
out.SSLCertificate = in.SSLCertificate
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2691,6 +2692,7 @@ func autoConvert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec(
|
||||||
out.Type = LoadBalancerType(in.Type)
|
out.Type = LoadBalancerType(in.Type)
|
||||||
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
||||||
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
||||||
|
out.SSLCertificate = in.SSLCertificate
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,7 @@ type LoadBalancerAccessSpec struct {
|
||||||
Type LoadBalancerType `json:"type,omitempty"`
|
Type LoadBalancerType `json:"type,omitempty"`
|
||||||
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
|
||||||
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
|
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
|
||||||
|
SSLCertificate string `json:"sslCertificate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeDNSConfig defines the kube dns configuration
|
// KubeDNSConfig defines the kube dns configuration
|
||||||
|
|
|
@ -2943,6 +2943,7 @@ func autoConvert_v1alpha2_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(
|
||||||
out.Type = kops.LoadBalancerType(in.Type)
|
out.Type = kops.LoadBalancerType(in.Type)
|
||||||
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
||||||
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
||||||
|
out.SSLCertificate = in.SSLCertificate
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2955,6 +2956,7 @@ func autoConvert_kops_LoadBalancerAccessSpec_To_v1alpha2_LoadBalancerAccessSpec(
|
||||||
out.Type = LoadBalancerType(in.Type)
|
out.Type = LoadBalancerType(in.Type)
|
||||||
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
|
||||||
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
|
||||||
|
out.SSLCertificate = in.SSLCertificate
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kops/pkg/acls"
|
"k8s.io/kops/pkg/acls"
|
||||||
kops "k8s.io/kops/pkg/apis/kops"
|
"k8s.io/kops/pkg/apis/kops"
|
||||||
"k8s.io/kops/pkg/apis/kops/v1alpha2"
|
"k8s.io/kops/pkg/apis/kops/v1alpha2"
|
||||||
"k8s.io/kops/pkg/kopscodecs"
|
"k8s.io/kops/pkg/kopscodecs"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"k8s.io/kops/util/pkg/vfs"
|
||||||
|
|
|
@ -85,7 +85,8 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se
|
||||||
|
|
||||||
b.Context = clusterName
|
b.Context = clusterName
|
||||||
|
|
||||||
{
|
// add the CA Cert to the kubeconfig only if we didn't specify a SSL cert for the LB
|
||||||
|
if cluster.Spec.API == nil || cluster.Spec.API.LoadBalancer == nil || cluster.Spec.API.LoadBalancer.SSLCertificate == "" {
|
||||||
cert, _, _, err := keyStore.FindKeypair(fi.CertificateId_CA)
|
cert, _, _, err := keyStore.FindKeypair(fi.CertificateId_CA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error fetching CA keypair: %v", err)
|
return nil, fmt.Errorf("error fetching CA keypair: %v", err)
|
||||||
|
|
|
@ -102,6 +102,14 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
idleTimeout = time.Second * time.Duration(*lbSpec.IdleTimeoutSeconds)
|
idleTimeout = time.Second * time.Duration(*lbSpec.IdleTimeoutSeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listeners := map[string]*awstasks.LoadBalancerListener{
|
||||||
|
"443": {InstancePort: 443},
|
||||||
|
}
|
||||||
|
|
||||||
|
if lbSpec.SSLCertificate != "" {
|
||||||
|
listeners["443"] = &awstasks.LoadBalancerListener{InstancePort: 443, SSLCertificateID: lbSpec.SSLCertificate}
|
||||||
|
}
|
||||||
|
|
||||||
elb = &awstasks.LoadBalancer{
|
elb = &awstasks.LoadBalancer{
|
||||||
Name: s("api." + b.ClusterName()),
|
Name: s("api." + b.ClusterName()),
|
||||||
Lifecycle: b.Lifecycle,
|
Lifecycle: b.Lifecycle,
|
||||||
|
@ -110,10 +118,8 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
SecurityGroups: []*awstasks.SecurityGroup{
|
SecurityGroups: []*awstasks.SecurityGroup{
|
||||||
b.LinkToELBSecurityGroup("api"),
|
b.LinkToELBSecurityGroup("api"),
|
||||||
},
|
},
|
||||||
Subnets: elbSubnets,
|
Subnets: elbSubnets,
|
||||||
Listeners: map[string]*awstasks.LoadBalancerListener{
|
Listeners: listeners,
|
||||||
"443": {InstancePort: 443},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Configure fast-recovery health-checks
|
// Configure fast-recovery health-checks
|
||||||
HealthCheck: &awstasks.LoadBalancerHealthCheck{
|
HealthCheck: &awstasks.LoadBalancerHealthCheck{
|
||||||
|
|
|
@ -71,7 +71,6 @@ func hasPlaceHolderIP(clusterName string) (bool, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, fmt.Errorf("unable to parse Kubernetes cluster API URL: %v", err)
|
return true, fmt.Errorf("unable to parse Kubernetes cluster API URL: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hostAddrs, err := net.LookupHost(apiAddr.Hostname())
|
hostAddrs, err := net.LookupHost(apiAddr.Hostname())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, fmt.Errorf("unable to resolve Kubernetes cluster API URL dns: %v", err)
|
return true, fmt.Errorf("unable to resolve Kubernetes cluster API URL dns: %v", err)
|
||||||
|
|
|
@ -58,12 +58,12 @@ type LoadBalancer struct {
|
||||||
|
|
||||||
Scheme *string
|
Scheme *string
|
||||||
|
|
||||||
HealthCheck *LoadBalancerHealthCheck
|
HealthCheck *LoadBalancerHealthCheck
|
||||||
AccessLog *LoadBalancerAccessLog
|
AccessLog *LoadBalancerAccessLog
|
||||||
//AdditionalAttributes []*LoadBalancerAdditionalAttribute
|
|
||||||
ConnectionDraining *LoadBalancerConnectionDraining
|
ConnectionDraining *LoadBalancerConnectionDraining
|
||||||
ConnectionSettings *LoadBalancerConnectionSettings
|
ConnectionSettings *LoadBalancerConnectionSettings
|
||||||
CrossZoneLoadBalancing *LoadBalancerCrossZoneLoadBalancing
|
CrossZoneLoadBalancing *LoadBalancerCrossZoneLoadBalancing
|
||||||
|
SSLCertificateID string
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ fi.CompareWithID = &LoadBalancer{}
|
var _ fi.CompareWithID = &LoadBalancer{}
|
||||||
|
@ -73,17 +73,17 @@ func (e *LoadBalancer) CompareWithID() *string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoadBalancerListener struct {
|
type LoadBalancerListener struct {
|
||||||
InstancePort int
|
InstancePort int
|
||||||
|
SSLCertificateID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *LoadBalancerListener) mapToAWS(loadBalancerPort int64) *elb.Listener {
|
func (e *LoadBalancerListener) mapToAWS(loadBalancerPort int64) *elb.Listener {
|
||||||
return &elb.Listener{
|
return &elb.Listener{
|
||||||
LoadBalancerPort: aws.Int64(loadBalancerPort),
|
LoadBalancerPort: aws.Int64(loadBalancerPort),
|
||||||
|
Protocol: aws.String("SSL"),
|
||||||
Protocol: aws.String("TCP"),
|
InstanceProtocol: aws.String("SSL"),
|
||||||
|
|
||||||
InstanceProtocol: aws.String("TCP"),
|
|
||||||
InstancePort: aws.Int64(int64(e.InstancePort)),
|
InstancePort: aws.Int64(int64(e.InstancePort)),
|
||||||
|
SSLCertificateId: aws.String(e.SSLCertificateID),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,16 +334,6 @@ func (e *LoadBalancer) Find(c *fi.Context) (*LoadBalancer, error) {
|
||||||
actual.AccessLog.S3BucketPrefix = lbAttributes.AccessLog.S3BucketPrefix
|
actual.AccessLog.S3BucketPrefix = lbAttributes.AccessLog.S3BucketPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't map AdditionalAttributes - yet
|
|
||||||
//var additionalAttributes []*LoadBalancerAdditionalAttribute
|
|
||||||
//for index, additionalAttribute := range lbAttributes.AdditionalAttributes {
|
|
||||||
// additionalAttributes[index] = &LoadBalancerAdditionalAttribute{
|
|
||||||
// Key: additionalAttribute.Key,
|
|
||||||
// Value: additionalAttribute.Value,
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//actual.AdditionalAttributes = additionalAttributes
|
|
||||||
|
|
||||||
actual.ConnectionDraining = &LoadBalancerConnectionDraining{}
|
actual.ConnectionDraining = &LoadBalancerConnectionDraining{}
|
||||||
if lbAttributes.ConnectionDraining.Enabled != nil {
|
if lbAttributes.ConnectionDraining.Enabled != nil {
|
||||||
actual.ConnectionDraining.Enabled = lbAttributes.ConnectionDraining.Enabled
|
actual.ConnectionDraining.Enabled = lbAttributes.ConnectionDraining.Enabled
|
||||||
|
@ -381,7 +371,7 @@ func (e *LoadBalancer) Find(c *fi.Context) (*LoadBalancer, error) {
|
||||||
// 1. We don't want to force a rename of the ELB, because that is a destructive operation
|
// 1. We don't want to force a rename of the ELB, because that is a destructive operation
|
||||||
// 2. We were creating ELBs with insufficiently qualified names previously
|
// 2. We were creating ELBs with insufficiently qualified names previously
|
||||||
if fi.StringValue(e.LoadBalancerName) != fi.StringValue(actual.LoadBalancerName) {
|
if fi.StringValue(e.LoadBalancerName) != fi.StringValue(actual.LoadBalancerName) {
|
||||||
glog.V(2).Infof("Resuing existing load balancer with name: %q", actual.LoadBalancerName)
|
glog.V(2).Infof("Reusing existing load balancer with name: %q", actual.LoadBalancerName)
|
||||||
e.LoadBalancerName = actual.LoadBalancerName
|
e.LoadBalancerName = actual.LoadBalancerName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,11 +443,7 @@ func (s *LoadBalancer) CheckChanges(a, e, changes *LoadBalancer) error {
|
||||||
return fi.RequiredField("ConnectionDraining.Enabled")
|
return fi.RequiredField("ConnectionDraining.Enabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if e.ConnectionSettings != nil {
|
|
||||||
// if e.ConnectionSettings.IdleTimeout == nil {
|
|
||||||
// return fi.RequiredField("ConnectionSettings.IdleTimeout")
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
if e.CrossZoneLoadBalancing != nil {
|
if e.CrossZoneLoadBalancing != nil {
|
||||||
if e.CrossZoneLoadBalancing.Enabled == nil {
|
if e.CrossZoneLoadBalancing.Enabled == nil {
|
||||||
return fi.RequiredField("CrossZoneLoadBalancing.Enabled")
|
return fi.RequiredField("CrossZoneLoadBalancing.Enabled")
|
||||||
|
@ -558,6 +544,20 @@ func (_ *LoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *LoadBalan
|
||||||
}
|
}
|
||||||
|
|
||||||
if changes.Listeners != nil {
|
if changes.Listeners != nil {
|
||||||
|
|
||||||
|
elbDescription, err := findLoadBalancerByLoadBalancerName(t.Cloud, loadBalancerName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting load balancer by name: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if elbDescription != nil {
|
||||||
|
// deleting the listener before recreating it
|
||||||
|
t.Cloud.ELB().DeleteLoadBalancerListeners(&elb.DeleteLoadBalancerListenersInput{
|
||||||
|
LoadBalancerName: aws.String(loadBalancerName),
|
||||||
|
LoadBalancerPorts: []*int64{aws.Int64(443)},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
request := &elb.CreateLoadBalancerListenersInput{}
|
request := &elb.CreateLoadBalancerListenersInput{}
|
||||||
request.LoadBalancerName = aws.String(loadBalancerName)
|
request.LoadBalancerName = aws.String(loadBalancerName)
|
||||||
|
|
||||||
|
@ -572,7 +572,7 @@ func (_ *LoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *LoadBalan
|
||||||
|
|
||||||
glog.V(2).Infof("Creating LoadBalancer listeners")
|
glog.V(2).Infof("Creating LoadBalancer listeners")
|
||||||
|
|
||||||
_, err := t.Cloud.ELB().CreateLoadBalancerListeners(request)
|
_, err = t.Cloud.ELB().CreateLoadBalancerListeners(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating LoadBalancerListeners: %v", err)
|
return fmt.Errorf("error creating LoadBalancerListeners: %v", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue