Skip to content
This repository has been archived by the owner on Apr 7, 2020. It is now read-only.

Commit

Permalink
Allow addings zones for AWS infra
Browse files Browse the repository at this point in the history
  • Loading branch information
timuthy committed Nov 20, 2019
1 parent b333930 commit 81d31ba
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 15 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -262,5 +262,5 @@ start-gardener-validator-aws:
-ldflags $(LD_FLAGS) \
./controllers/provider-aws/cmd/gardener-validator-aws \
--webhook-config-server-host=0.0.0.0 \
--webhook-config-server-port=8443 \
--webhook-config-cert-dir=$(CERT_DIR)
--webhook-config-server-port=9443 \
--webhook-config-cert-dir=./controllers/provider-aws/example/validator-aws-certs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: gardener-validator-aws
webhooks:
- name: validation.aws.provider.extensions.gardener.cloud
rules:
- apiGroups:
- "core.gardener.cloud"
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- shoots
failurePolicy: Fail
clientConfig:
url: "https://localhost:9443/webhooks/validate-shoot-aws"
caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUU0akNDQXNvQ0NRRHVLOTQ5QnF0eUt6QU5CZ2txaGtpRzl3MEJBUXNGQURBek1Sb3dHQVlEVlFRS0RCRkgKWVhKa1pXNWxjaUJGZUdGdGNHeGxjekVWTUJNR0ExVUVDd3dNVUhKdmRtbGtaWElnUVZkVE1CNFhEVEU1TVRFeQpNREV4TURRd00xb1hEVEk1TVRFeE56RXhNRFF3TTFvd016RWFNQmdHQTFVRUNnd1JSMkZ5WkdWdVpYSWdSWGhoCmJYQnNaWE14RlRBVEJnTlZCQXNNREZCeWIzWnBaR1Z5SUVGWFV6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQUQKZ2dJUEFEQ0NBZ29DZ2dJQkFOV0UrY0F4MGg3b1pQems4UzdWY3lsbUx3YVZ3SU9BZkpkd0NSYkpuUmZNbm1RUQpqNWFaeExqN3VGR2ZhMmdxeDNFZkxZNU1YYXA1V21GSUVNM0Y4N1AxdmRzRU1lRW9ndUNLb0NsVk95cGZLQnZQCm10cXRDUWEzK3dwOUwvSlg3dGZubmJKQVZ3RTF0RzY4Mk5OajVwaVIxUXlrc1dXTGl6MFpMdG1MaFR1QlgxQWgKOW9vWnNTZy9FS1JkUmZvU1hGUWE3bFlmTkthVWNuRUNDSnNtQ0l2NjNJWFo0T1dHWU85aXNwRENkZ3ZPMFRCeApwZ3Q0NUZuUmQ5U1lhTE1kanY2WGNaL0hmYmFhWHk0QUZIeU5Lb1NaWVZxUDg0TVVia1BGQkhHZ1ZERENCa3VSCm9tOTVxb1BTK2Q0S0dCN1BnV1VnaXJLVWFpWHdIeWNNUFQ1d0Y3ZHpFWjdtUnNTakpTR1ZpK2NXZnRuMjBBNjAKanp4aG95UjZNb09nSFp6QTd2VC84THpPcDBhQXR6TFhIakJzZ1pJMlhYcU9oS01LL1BSRFE3WlRxdGo1WFpsZQo4c3hPMG51VFlaQllMcjFYTGkrYWU2ZmxtTXozeUZPMmZMR2R0dzRmMFI4Ky85aERZUEFhNHluRFBZWVdnbFVXCnJqWjFXZGptMG12bXAvaDVNeFJCbjlzTFVKb0tUVWV6Q0dzcDBXRkx4MG1BZHYxTjZIZVpUaDVxWG1XdWpjdWkKeGlXcUVNaVlWcGJhTmpWTm1OQWhUUDY4VWNkVEhRQUpnYlU5SVY4TmtmYklIcFRjY3FFaGFqUmFFdmo0SmlIbApnUzQ0V0d6VzQ0SjJKdHJzamZlYVRKZWtpbFh0WjNVdFAreXUxUjZ0NlJyQmc2bmNySmVySWRQc1RkZ0pBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnSUJBSzRyYUVmMEI0dGJzakhiNmIxa0hUVnMyKyt5QjdXMmVxWTgKSUtpZE1VcEFSSjhSWmVZVEh5N0lFUHZYQUQ4aW9IOW1Pd1dPT2ZyRUdCN2pBUjJCb1IyR2ZSd3hoM3RWM0RLdgoydEZZeGVKWlNuTEFuZmNLQzFlZ3duT1JuOTRjRk54bkhOQkRjS2RiU3FHL2VSNFdpVWdjV1YwbmNqVHNTUXZjCnMrdkd1WlQwUFlLcmxHYlB4VkhXSkJEdXFCQ3djczhIWEk4NzlSS3JmMTZOWVZEay9vTE5wUXV1V2NDQ0pDQzMKaWxnMTFGbkR6L1ZBMkppMWdhbGtwZEVxMHVKemlmcnY4S0ZrdmF3TUlFRWdCMTYwQnFrNmdsdkt5dWVUSHFLYQpuaCtJV3IzYlY1VHQ4QXNPdFZCdWJxempHOU9VU2g1LzZYT0FyTXhTaXBwT2llYmNYcFhrZWMyTldMRGNnQjlrCjB1T1FrTzZvUjBxZlFobXAwTEpsaEhCVGNHZkJsK3Yzd1B2RE5KS1hTM2xMVWg3L0J3d0piR3M0Mzd4TU10M1cKaGdzNTJWU0k1RU5EU2lmelplcnJzTXlQYzhHcXJ0NFhkYVRBU3VYNTlja0VDaUxSemFBbS9QQVl2N0Ntd0dvYQpLc0tOMzdZQWgrVXVONVc4Q3BLMzhFbG9Uc0ZVRzl0WEhYWmU5UG4wRjlXQU9Sb3YzVmlHTVZhZERmMzlmRDdzCjAwd1JrTnFNQy9CVFBtcHBqWXRieDQ1M2M3TWZrOGNNa0pnMGdTZnh3d2h0QUtibEszeXNOK3JsbnBMUDRPR0UKZHY4WHpKMUIrZVdzT3ZUcDI0TkRWZnJvQjFWbklmaDVKdnpiV1JZdjlLL09zdHBmWHgzZWRFR1p3djgxTnNHTQoxd0JSVkpJUgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
23 changes: 23 additions & 0 deletions controllers/provider-aws/example/validator-aws-certs/tls.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDwzCCAasCCQC8zKHK1l+1WzANBgkqhkiG9w0BAQsFADAzMRowGAYDVQQKDBFH
YXJkZW5lciBFeGFtcGxlczEVMBMGA1UECwwMUHJvdmlkZXIgQVdTMB4XDTE5MTEy
MDExMDY1M1oXDTI5MTExNzExMDY1M1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1n76AhTFkX6VDkJZQSaf9Woy
+vquQtkRbCfjLSuRJc3BCqHs6aPwwUkWGu0fs0DlLtlwj73PDEXXH1vcjJtgktnc
ledZx7zMqsZ18sL7SJuvt+UictFIkGdVD18CDnd8pYDSmWrTX4NrKYwDciIHjqcd
5bKugdH/4cZHGVv2zHfICKTW5CyiX/qwtVrgC5GeEyc8Ayl+pITUSxAlj6gcFmRB
ANDNh2HF3sxwkt1+xM2xOZVQtFiM4mRMcn0yu0DNJzW3sXNAUH3m1emVpG6I8Mns
kRwC6GupFsgpWQy2zl8u7XaFIwRHvrMAtUpGaRQCA7a0nWySVKZDBsXQdtVLRwID
AQABMA0GCSqGSIb3DQEBCwUAA4ICAQBM6cRiTAv+lqDhfEvIU2OMBP6Rb4WebAi7
qCMHAiTl0hCSDO3ZlFVl73OduOENdDvupMGmez0Zjy5Tz9RiU8x4bt93DbAuOAQF
hOhLvDuZM9p10z1RBoeshyG42JQHAws3qM8hTpdQSrClO+Q21meEGYPYr4stYdeK
5SoZG/Wu9j+jtvylkJNJgoTWHyuDm2C6NakBh6M5aJS28eXgUOQ9IwH9+7pYS+Ow
QHNvAjffo67oXBxVWnbpMmymtTutpuf5QMbb0GSX6sad9oTm5vSXWHJYvg5nCZ7d
dn2lsYjP5ishHy+Kr6vTkYdSRiFgQEyLnk72fIdn2RvsW9073Y6CGpgxSQMhz9tT
L/J43Ym1yTJH1DDDraMJsn7uUERFY7B+h3ZWQ3mmafR2w6VbLlHMJmAhlmFLL9dv
lDDBXr0mwgVEFLiKWQhBc6++AgDcog/J21sGdHiASw7wywf+FaSr+UnPZ27mk74Z
IDNzsP9WULgqGYsS/zCHdeGw3YNgaq/XNpaG+qi5iuqiAPgP66mir9tICJndC+lW
ffgjRcuG8AK366Fx8GtfQ4SJEfVBK+ZNpfDsctHrMCRMlhB0V7JNgPIqnMUVdHUI
QGwKo8OSoyNFL/8QjaHBgNkWlskvvIPPIKjkVTUZUUvoOWWODzv3tw0pht/aEHXe
14bwn68m4Q==
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions controllers/provider-aws/example/validator-aws-certs/tls.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA1n76AhTFkX6VDkJZQSaf9Woy+vquQtkRbCfjLSuRJc3BCqHs
6aPwwUkWGu0fs0DlLtlwj73PDEXXH1vcjJtgktncledZx7zMqsZ18sL7SJuvt+Ui
ctFIkGdVD18CDnd8pYDSmWrTX4NrKYwDciIHjqcd5bKugdH/4cZHGVv2zHfICKTW
5CyiX/qwtVrgC5GeEyc8Ayl+pITUSxAlj6gcFmRBANDNh2HF3sxwkt1+xM2xOZVQ
tFiM4mRMcn0yu0DNJzW3sXNAUH3m1emVpG6I8MnskRwC6GupFsgpWQy2zl8u7XaF
IwRHvrMAtUpGaRQCA7a0nWySVKZDBsXQdtVLRwIDAQABAoIBABCrO3iP7q6Y3LKH
+3Gxs7qZry6L7qDpR45VJzVqblQ2wiq2XLfncp1CtcIP7We7wlO6uCGjiYSVpNse
A2y14nJnFdpcaUC5blpTI/Viq65/0s8CsoOjufTm4thX9Mv1Ay3FbhhYEecZSmmn
JNloxZeTayJfmWojTLRZ+UqCOBK5k9h0Kno7M5M3pew46MOhULqGa7WzIK2mCbYY
mY6QrScP2+i7ocUi0wK25cIEMAHJu/6p+Zo2UaSCMnfrFpklMThu6Klc0oQFQSJI
Yal/cqGchB4wzn0hbZgNtkuZefbWvrCnu+hpQofAVN4x+4LN6b+YMkQshIDf3j9v
48iKWkkCgYEA7Uz1rkY9BfpnP2RFzAhX4uaDjjk9mcyK09fhPhr8PtjAbHBVT32v
Maxwj746VxhFrOUlJZ/5tsvjoN2UyKWiCWyYb79ZcAevqCkna1in52Wd0mHb9YYY
aMAVjOyocRZvv+bCMgF5jBJ0EKEhlu4mIM7vtRs097nO8heelpPmtWUCgYEA52X7
UE5uypG/auOp6enjTrXbAkc9jj+JcK9imBQzcXxR5lQWO7MceuLk+kThyLl2YoGt
oQrS9LU/bWXhzb+TsBgZ1UcGRED50R7Is9PJo/QRbNXIPIkvLMLnK7alCSIcF770
b0WskH6cs4h61VcrYFntDkSaZBkJudJx6K/OOTsCgYAyQt+yluvr7TqbIajq60V6
KKrqn9MdVUZ+UjZCCkMtKImxLiXTnWJTGhwJRhhjRB/V2/7/NiAVCKBg/S27ReHJ
LzgmSxgtc2NQMc9InFGL4GkKG3IUUd+vqCeoXqPauA7ZTY4KO2e8NFhjAU31AuIO
huYcrPOOGMvtWPVdHVx7RQKBgFLVKtVgfkB9U+xLevOFCh2O88so/VwCWoy/+6c8
8/1X52lwCFVulG9Y8Wa1aa2U1lAE48aWPVXj28Sph99DCPcsaXLzbcbZC5RUVLwq
wC+0mtg+3uLsqLp5Oo9nXkSatTu6231Jj7BZ4nZSEMZ14c0n47gLzsiuPdELCEOn
S0cpAoGAL9PGWkxJvZjaoOlCVzWjngMaG4B2U8kFXD3HCJVV3JFxSG3mvCUaQRRP
Q9Szf7CqTxcw6JAZH5GQnQIJBHC3wZSov3e/IshzYlCexYsk95Y/X0buI9rOhQEj
CCNgNMhfvPMI2qjW3zI+btRhngZwDQ7QBgM5ZvArYZuNqGsH0AM=
-----END RSA PRIVATE KEY-----
36 changes: 32 additions & 4 deletions controllers/provider-aws/pkg/apis/aws/validation/infrastructure.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,27 @@ func ValidateInfrastructureConfig(infra *apisaws.InfrastructureConfig, nodesCIDR
workerCIDRs = make([]cidrvalidation.CIDR, 0, len(infra.Networks.Zones))
)

validatedZones := sets.NewString()
for i, zone := range infra.Networks.Zones {
internalPath := networksPath.Child("zones").Index(i).Child("internal")
zonePath := networksPath.Child("zones").Index(i)
if validatedZones.Has(zone.Name) {
allErrs = append(allErrs, field.Invalid(zonePath.Child("name"), zone.Name, "each zone may only be specified once"))
}

internalPath := zonePath.Child("internal")
cidrs = append(cidrs, cidrvalidation.NewCIDR(zone.Internal, internalPath))
allErrs = append(allErrs, cidrvalidation.ValidateCIDRIsCanonical(internalPath, zone.Internal)...)

publicPath := networksPath.Child("zones").Index(i).Child("public")
publicPath := zonePath.Child("public")
cidrs = append(cidrs, cidrvalidation.NewCIDR(zone.Public, publicPath))
allErrs = append(allErrs, cidrvalidation.ValidateCIDRIsCanonical(publicPath, zone.Public)...)

workerPath := networksPath.Child("zones").Index(i).Child("workers")
workerPath := zonePath.Child("workers")
cidrs = append(cidrs, cidrvalidation.NewCIDR(zone.Workers, workerPath))
allErrs = append(allErrs, cidrvalidation.ValidateCIDRIsCanonical(workerPath, zone.Workers)...)
workerCIDRs = append(workerCIDRs, cidrvalidation.NewCIDR(zone.Workers, workerPath))

validatedZones.Insert(zone.Name)
}

allErrs = append(allErrs, cidrvalidation.ValidateCIDRParse(cidrs...)...)
Expand Down Expand Up @@ -133,7 +141,27 @@ func ValidateInfrastructureConfig(infra *apisaws.InfrastructureConfig, nodesCIDR
func ValidateInfrastructureConfigUpdate(oldConfig, newConfig *apisaws.InfrastructureConfig, nodesCIDR, podsCIDR, servicesCIDR *string) field.ErrorList {
allErrs := field.ErrorList{}

allErrs = append(allErrs, apivalidation.ValidateImmutableField(newConfig.Networks, oldConfig.Networks, field.NewPath("networks"))...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(newConfig.Networks.VPC, oldConfig.Networks.VPC, field.NewPath("networks.vpc"))...)

var (
oldZones = oldConfig.Networks.Zones
newZones = newConfig.Networks.Zones
missingZones = sets.NewString()
)

for i, oldZone := range oldZones {
missingZones.Insert(oldZone.Name)
for j, newZone := range newZones {
if newZone.Name == oldZone.Name {
missingZones.Delete(newZone.Name)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(newConfig.Networks.Zones[j], oldConfig.Networks.Zones[j], field.NewPath("networks.zones").Index(i))...)
}
}
}

for zone := range missingZones {
allErrs = append(allErrs, field.Invalid(field.NewPath("networks.zones"), zone, "zone is missing - removing a zone is not supported"))
}

return allErrs
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ var _ = Describe("InfrastructureConfig validation", func() {
vpc = "10.0.0.0/8"
invalidCIDR = "invalid-cidr"
zone = "zone1"
zone2 = "zone2"

awsZone2 = apisaws.Zone{
Name: zone2,
Internal: "10.250.4.0/24",
Public: "10.250.5.0/24",
Workers: "10.250.6.0/24",
}
)

BeforeEach(func() {
Expand All @@ -62,7 +70,6 @@ var _ = Describe("InfrastructureConfig validation", func() {
shoot *gardencorev1alpha1.Shoot
region = "eu-west"
region2 = "us-west"
zone2 = "zone2"
)
Context("zones validation", func() {
BeforeEach(func() {
Expand Down Expand Up @@ -120,6 +127,34 @@ var _ = Describe("InfrastructureConfig validation", func() {
})

Describe("#ValidateInfrastructureConfig", func() {
Context("Zones", func() {
It("should forbid empty zones", func() {
infrastructureConfig.Networks.Zones = nil

errorList := ValidateInfrastructureConfig(infrastructureConfig, &nodes, &pods, &services)

Expect(errorList).To(ConsistOfFields(Fields{
"Type": Equal(field.ErrorTypeRequired),
"Field": Equal("networks.zones"),
"Detail": Equal("must specify at least the networks for one zone"),
}))

})

It("should forbid adding a zone", func() {
infrastructureConfig.Networks.Zones = append(infrastructureConfig.Networks.Zones, awsZone2)
infrastructureConfig.Networks.Zones[1].Name = zone

errorList := ValidateInfrastructureConfig(infrastructureConfig, &nodes, &pods, &services)

Expect(errorList).To(ConsistOfFields(Fields{
"Type": Equal(field.ErrorTypeInvalid),
"Field": Equal("networks.zones[1].name"),
"Detail": Equal("each zone may only be specified once"),
}))
})
})

Context("CIDR", func() {
It("should forbid invalid VPC CIDRs", func() {
infrastructureConfig.Networks.VPC.CIDR = &invalidCIDR
Expand Down Expand Up @@ -302,7 +337,17 @@ var _ = Describe("InfrastructureConfig validation", func() {
Expect(ValidateInfrastructureConfigUpdate(infrastructureConfig, infrastructureConfig, &nodes, &pods, &services)).To(BeEmpty())
})

It("should forbid changing the network section", func() {
It("should allow adding a zone", func() {

newInfrastructureConfig := infrastructureConfig.DeepCopy()
newInfrastructureConfig.Networks.Zones = append(newInfrastructureConfig.Networks.Zones, awsZone2)

errorList := ValidateInfrastructureConfigUpdate(infrastructureConfig, newInfrastructureConfig, &nodes, &pods, &services)

Expect(errorList).To(BeEmpty())
})

It("should forbid changing the VPC", func() {
newInfrastructureConfig := infrastructureConfig.DeepCopy()
newCIDR := "1.2.3.4/5"
newInfrastructureConfig.Networks.VPC.CIDR = &newCIDR
Expand All @@ -311,7 +356,31 @@ var _ = Describe("InfrastructureConfig validation", func() {

Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeInvalid),
"Field": Equal("networks"),
"Field": Equal("networks.vpc"),
}))))
})

It("should forbid changing the zone information", func() {
newInfrastructureConfig := infrastructureConfig.DeepCopy()
newInfrastructureConfig.Networks.Zones[0].Internal = "10.250.2.0/24"

errorList := ValidateInfrastructureConfigUpdate(infrastructureConfig, newInfrastructureConfig, &nodes, &pods, &services)

Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeInvalid),
"Field": Equal("networks.zones[0]"),
}))))
})

It("should forbid removing a zone", func() {
newInfrastructureConfig := infrastructureConfig.DeepCopy()
newInfrastructureConfig.Networks.Zones[0] = awsZone2

errorList := ValidateInfrastructureConfigUpdate(infrastructureConfig, newInfrastructureConfig, &nodes, &pods, &services)

Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeInvalid),
"Field": Equal("networks.zones"),
}))))
})
})
Expand Down
15 changes: 9 additions & 6 deletions controllers/provider-aws/pkg/validator/shoot_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ func (v *Shoot) Handle(ctx context.Context, req admission.Request) admission.Res
return admission.Allowed("webhook not responsible for this provider")
}

if req.Operation == admissionv1beta1.Update {
switch req.Operation {
case admissionv1beta1.Create:
if err := v.validateShoot(ctx, shoot); err != nil {
v.Logger.Error(err, "denied request")
return admission.Errored(http.StatusBadRequest, err)
}
case admissionv1beta1.Update:
oldShoot := &gardencorev1alpha1.Shoot{}
_, _, err := v.decoder.Decode(req.OldObject.Raw, nil, oldShoot)
if err != nil {
Expand All @@ -62,11 +68,8 @@ func (v *Shoot) Handle(ctx context.Context, req admission.Request) admission.Res
v.Logger.Error(err, "denied request")
return admission.Errored(http.StatusBadRequest, err)
}
}

if err := v.validateShoot(ctx, shoot); err != nil {
v.Logger.Error(err, "denied request")
return admission.Errored(http.StatusBadRequest, err)
default:
v.Logger.Info("Webhook not responsible", "Operation", req.Operation)
}

return admission.Allowed("validations succeeded")
Expand Down

0 comments on commit 81d31ba

Please sign in to comment.