Added initial implementation of ACM cert for Kubernetes API ELB

This commit is contained in:
Raffaele Di Fazio 2018-07-06 09:29:54 +02:00
parent f495c952a7
commit d477e96c38
12 changed files with 39 additions and 31 deletions

View File

@ -158,6 +158,7 @@ func RunCreate(f *util.Factory, out io.Writer, c *CreateOptions) error {
case *kopsapi.Cluster:
// Adding a PerformAssignments() call here as the user might be trying to use
// the new `-f` feature, with an old cluster definition.
err = cloudup.PerformAssignments(v)
if err != nil {
return fmt.Errorf("error populating configuration: %v", err)

View File

@ -123,6 +123,9 @@ type CreateClusterOptions struct {
// Specify API loadbalancer as public or internal
APILoadBalancerType string
// Specify the SSL certificate to use for the API loadbalancer. Currently only supported in AWS.
APISSLCertificate string
// Allow custom public master name
MasterPublicName string
@ -327,6 +330,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.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, "Sets the SSL Certificate to use for the API server loadbalancer. Currently only supported in AWS.")
// Allow custom public master name
cmd.Flags().StringVar(&options.MasterPublicName, "master-public-name", options.MasterPublicName, "Sets the public master public name")
@ -1052,6 +1056,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
cluster.Spec.IAM = &api.IAMSpec{
AllowContainerRegistry: true,

View File

@ -282,6 +282,7 @@ type LoadBalancerAccessSpec struct {
Type LoadBalancerType `json:"type,omitempty"`
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
SSLCertificate string `json:"sslCertificate,omitempty"`
}
// KubeDNSConfig defines the kube dns configuration

View File

@ -281,6 +281,7 @@ type LoadBalancerAccessSpec struct {
Type LoadBalancerType `json:"type,omitempty"`
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
SSLCertificate string `json:"sslCertificate,omitempty"`
}
// KubeDNSConfig defines the kube dns configuration

View File

@ -2462,6 +2462,7 @@ func autoConvert_v1alpha1_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(
out.Type = kops.LoadBalancerType(in.Type)
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
out.SSLCertificate = in.SSLCertificate
return nil
}
@ -2474,6 +2475,7 @@ func autoConvert_kops_LoadBalancerAccessSpec_To_v1alpha1_LoadBalancerAccessSpec(
out.Type = LoadBalancerType(in.Type)
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
out.SSLCertificate = in.SSLCertificate
return nil
}

View File

@ -282,6 +282,7 @@ type LoadBalancerAccessSpec struct {
Type LoadBalancerType `json:"type,omitempty"`
IdleTimeoutSeconds *int64 `json:"idleTimeoutSeconds,omitempty"`
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
SSLCertificate string `json:"sslCertificate,omitempty"`
}
type KubeDNSConfig struct {

View File

@ -2726,6 +2726,7 @@ func autoConvert_v1alpha2_LoadBalancerAccessSpec_To_kops_LoadBalancerAccessSpec(
out.Type = kops.LoadBalancerType(in.Type)
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
out.SSLCertificate = in.SSLCertificate
return nil
}
@ -2738,6 +2739,7 @@ func autoConvert_kops_LoadBalancerAccessSpec_To_v1alpha2_LoadBalancerAccessSpec(
out.Type = LoadBalancerType(in.Type)
out.IdleTimeoutSeconds = in.IdleTimeoutSeconds
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
out.SSLCertificate = in.SSLCertificate
return nil
}

View File

@ -31,7 +31,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"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/kopscodecs"
"k8s.io/kops/util/pkg/vfs"

View File

@ -85,7 +85,8 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se
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.LoadBalancer.SSLCertificate == "" {
cert, _, _, err := keyStore.FindKeypair(fi.CertificateId_CA)
if err != nil {
return nil, fmt.Errorf("error fetching CA keypair: %v", err)

View File

@ -102,6 +102,14 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
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{
Name: s("api." + b.ClusterName()),
Lifecycle: b.Lifecycle,
@ -110,10 +118,8 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
SecurityGroups: []*awstasks.SecurityGroup{
b.LinkToELBSecurityGroup("api"),
},
Subnets: elbSubnets,
Listeners: map[string]*awstasks.LoadBalancerListener{
"443": {InstancePort: 443},
},
Subnets: elbSubnets,
Listeners: listeners,
// Configure fast-recovery health-checks
HealthCheck: &awstasks.LoadBalancerHealthCheck{

View File

@ -71,7 +71,6 @@ func hasPlaceHolderIP(clusterName string) (bool, error) {
if err != nil {
return true, fmt.Errorf("unable to parse Kubernetes cluster API URL: %v", err)
}
hostAddrs, err := net.LookupHost(apiAddr.Hostname())
if err != nil {
return true, fmt.Errorf("unable to resolve Kubernetes cluster API URL dns: %v", err)

View File

@ -58,12 +58,12 @@ type LoadBalancer struct {
Scheme *string
HealthCheck *LoadBalancerHealthCheck
AccessLog *LoadBalancerAccessLog
//AdditionalAttributes []*LoadBalancerAdditionalAttribute
HealthCheck *LoadBalancerHealthCheck
AccessLog *LoadBalancerAccessLog
ConnectionDraining *LoadBalancerConnectionDraining
ConnectionSettings *LoadBalancerConnectionSettings
CrossZoneLoadBalancing *LoadBalancerCrossZoneLoadBalancing
SSLCertificateID string
}
var _ fi.CompareWithID = &LoadBalancer{}
@ -73,17 +73,17 @@ func (e *LoadBalancer) CompareWithID() *string {
}
type LoadBalancerListener struct {
InstancePort int
InstancePort int
SSLCertificateID string
}
func (e *LoadBalancerListener) mapToAWS(loadBalancerPort int64) *elb.Listener {
return &elb.Listener{
LoadBalancerPort: aws.Int64(loadBalancerPort),
Protocol: aws.String("TCP"),
InstanceProtocol: aws.String("TCP"),
Protocol: aws.String("SSL"),
InstanceProtocol: aws.String("SSL"),
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
}
// 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{}
if lbAttributes.ConnectionDraining.Enabled != nil {
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
// 2. We were creating ELBs with insufficiently qualified names previously
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
}
@ -453,11 +443,7 @@ func (s *LoadBalancer) CheckChanges(a, e, changes *LoadBalancer) error {
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.Enabled == nil {
return fi.RequiredField("CrossZoneLoadBalancing.Enabled")