-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fb93486
commit e6427ed
Showing
5 changed files
with
236 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#!/bin/bash | ||
|
||
# Copyright The Shipwright Contributors | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
set -euo pipefail | ||
|
||
if ! hash jq >/dev/null 2>&1 ; then | ||
echo "[ERROR] jq is not installed" | ||
exit 1 | ||
fi | ||
|
||
if ! hash openssl >/dev/null 2>&1 ; then | ||
echo "[ERROR] openssl is not installed" | ||
exit 1 | ||
fi | ||
|
||
echo "[INFO] Generating key and signing request for Shipwright Build Webhook" | ||
|
||
cat <<EOF >/tmp/csr.conf | ||
[req] | ||
req_extensions = v3_req | ||
distinguished_name = req_distinguished_name | ||
[req_distinguished_name] | ||
[ v3_req ] | ||
basicConstraints = CA:FALSE | ||
keyUsage = digitalSignature, keyEncipherment | ||
extendedKeyUsage = serverAuth | ||
subjectAltName = @alt_names | ||
[alt_names] | ||
DNS.1 = host.docker.internal | ||
EOF | ||
|
||
openssl genrsa -out /tmp/server-key.pem 2048 | ||
openssl req -new -days 365 -key /tmp/server-key.pem -subj "/O=system:nodes/CN=system:node:host.docker.internal" -out /tmp/server.csr -config /tmp/csr.conf | ||
|
||
echo "[INFO] Deleting previous CertificateSigningRequest" | ||
kubectl delete csr shipwright-build-webhook-csr --ignore-not-found | ||
|
||
echo "[INFO] Create a CertificateSigningRequest" | ||
cat <<EOF | kubectl create -f - | ||
apiVersion: certificates.k8s.io/v1 | ||
kind: CertificateSigningRequest | ||
metadata: | ||
name: shipwright-build-webhook-csr | ||
spec: | ||
groups: | ||
- system:authenticated | ||
request: $(base64 </tmp/server.csr | tr -d '\n') | ||
signerName: kubernetes.io/kubelet-serving | ||
usages: | ||
- digital signature | ||
- key encipherment | ||
- server auth | ||
EOF | ||
|
||
echo "[INFO] Approve the CertificateSigningRequest" | ||
kubectl certificate approve shipwright-build-webhook-csr | ||
|
||
certificate="$(kubectl get csr shipwright-build-webhook-csr -o json | jq -r '.status.certificate')" | ||
while [ "${certificate}" == "null" ]; do | ||
echo "[INFO] Waiting for certificate to be ready" | ||
sleep 1 | ||
certificate="$(kubectl get csr shipwright-build-webhook-csr -o json | jq -r '.status.certificate')" | ||
done | ||
|
||
openssl base64 -d -A -out /tmp/server-cert.pem <<<"${certificate}" | ||
|
||
echo "[INFO] Deleting the CertificateSigningRequest" | ||
kubectl delete csr shipwright-build-webhook-csr --ignore-not-found | ||
rm -rf /tmp/csr.conf | ||
|
||
echo "[INFO] Retrieving CABundle" | ||
CA="$(kubectl get configmap -n kube-system extension-apiserver-authentication -o=jsonpath='{.data.client-ca-file}' | base64 | tr -d '\n')" | ||
|
||
echo "[INFO] Patching caBundle into CustomResourceDefinitions" | ||
kubectl patch crd clusterbuildstrategies.shipwright.io --type=json -p "[{\"op\":\"replace\",\"path\":\"/spec/conversion/webhook/clientConfig\",\"value\":{\"caBundle\":\"${CA}\",\"url\":\"https://host.docker.internal:30443/convert\"}}]" | ||
kubectl patch crd buildstrategies.shipwright.io --type=json -p "[{\"op\":\"replace\",\"path\":\"/spec/conversion/webhook/clientConfig\",\"value\":{\"caBundle\":\"${CA}\",\"url\":\"https://host.docker.internal:30443/convert\"}}]" | ||
kubectl patch crd builds.shipwright.io --type=json -p "[{\"op\":\"replace\",\"path\":\"/spec/conversion/webhook/clientConfig\",\"value\":{\"caBundle\":\"${CA}\",\"url\":\"https://host.docker.internal:30443/convert\"}}]" | ||
kubectl patch crd buildruns.shipwright.io --type=json -p "[{\"op\":\"replace\",\"path\":\"/spec/conversion/webhook/clientConfig\",\"value\":{\"caBundle\":\"${CA}\",\"url\":\"https://host.docker.internal:30443/convert\"}}]" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// Copyright The Shipwright Contributors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package utils | ||
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/shipwright-io/build/pkg/webhook/conversion" | ||
|
||
"github.com/onsi/ginkgo/v2" | ||
"github.com/onsi/gomega" | ||
) | ||
|
||
func StartBuildWebhook() *http.Server { | ||
mux := http.NewServeMux() | ||
mux.HandleFunc("/convert", conversion.CRDConvertHandler(context.Background())) | ||
mux.HandleFunc("/health", health) | ||
|
||
webhookServer := &http.Server{ | ||
Addr: ":30443", | ||
Handler: mux, | ||
ReadHeaderTimeout: 32 * time.Second, | ||
IdleTimeout: time.Second, | ||
TLSConfig: &tls.Config{ | ||
MinVersion: tls.VersionTLS12, | ||
CurvePreferences: []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.X25519}, | ||
CipherSuites: []uint16{ | ||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, | ||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, | ||
}, | ||
}, | ||
} | ||
|
||
// start server | ||
go func() { | ||
defer ginkgo.GinkgoRecover() | ||
|
||
if err := webhookServer.ListenAndServeTLS("/tmp/server-cert.pem", "/tmp/server-key.pem"); err != nil { | ||
if err != http.ErrServerClosed { | ||
gomega.Expect(err).ToNot(gomega.HaveOccurred()) | ||
} | ||
} | ||
}() | ||
|
||
client := &http.Client{ | ||
Transport: &http.Transport{ | ||
IdleConnTimeout: 5 * time.Second, | ||
ResponseHeaderTimeout: 5 * time.Second, | ||
TLSClientConfig: &tls.Config{ | ||
InsecureSkipVerify: true, | ||
MinVersion: tls.VersionTLS12, | ||
CurvePreferences: []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.X25519}, | ||
CipherSuites: []uint16{ | ||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, | ||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, | ||
}, | ||
}, | ||
TLSHandshakeTimeout: 5 * time.Second, | ||
}, | ||
} | ||
|
||
gomega.Eventually(func() int { | ||
r, err := client.Get("https://localhost:30443/health") | ||
if err != nil { | ||
return 0 | ||
} | ||
if r != nil { | ||
return r.StatusCode | ||
} | ||
return 0 | ||
}).WithTimeout(10 * time.Second).Should(gomega.Equal(http.StatusNoContent)) | ||
|
||
return webhookServer | ||
} | ||
|
||
func StopBuildWebhook(webhookServer *http.Server) { | ||
err := webhookServer.Close() | ||
gomega.Expect(err).ToNot(gomega.HaveOccurred()) | ||
|
||
client := &http.Client{ | ||
Transport: &http.Transport{ | ||
IdleConnTimeout: 5 * time.Second, | ||
ResponseHeaderTimeout: 5 * time.Second, | ||
TLSClientConfig: &tls.Config{ | ||
InsecureSkipVerify: true, | ||
MinVersion: tls.VersionTLS12, | ||
CurvePreferences: []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.X25519}, | ||
CipherSuites: []uint16{ | ||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | ||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, | ||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, | ||
}, | ||
}, | ||
TLSHandshakeTimeout: 5 * time.Second, | ||
}, | ||
} | ||
|
||
gomega.Eventually(func() int { | ||
r, err := client.Get("https://localhost:30443/health") | ||
if err != nil { | ||
return 0 | ||
} | ||
if r != nil { | ||
return r.StatusCode | ||
} | ||
return 0 | ||
}).WithTimeout(10 * time.Second).Should(gomega.Equal(0)) | ||
} | ||
|
||
func health(resp http.ResponseWriter, _ *http.Request) { | ||
resp.WriteHeader(http.StatusNoContent) | ||
} |