Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed webhook #342

Merged
merged 7 commits into from
Dec 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

ARG SPARK_IMAGE=gcr.io/spark-operator/spark:v2.4.0

FROM golang:1.10.2-alpine as builder
ARG DEP_VERSION="0.4.1"
FROM golang:1.11.2-alpine as builder
ARG DEP_VERSION="0.5.0"
RUN apk add --no-cache bash git
ADD https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 /usr/bin/dep
RUN chmod +x /usr/bin/dep
Expand All @@ -32,4 +32,6 @@ FROM ${SPARK_IMAGE}
COPY --from=builder /usr/bin/spark-operator /usr/bin/
RUN apk add --no-cache openssl curl
COPY hack/gencerts.sh /usr/bin/

ENTRYPOINT ["/usr/bin/spark-operator"]

77 changes: 45 additions & 32 deletions hack/gencerts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ function usage {
cat<< EOF
Usage: $SCRIPT
Options:
-h | --help Display help information.
-h | --help Display help information.
-n | --namespace <namespace> The namespace where the Spark operator is installed.
-s | --service <service> The name of the webhook service.
-p | --in-pod Whether the script is running inside a pod or not.
EOF
}

function parse_arguments {
while [ $# -gt 0 ]
while [[ $# -gt 0 ]]
do
case "$1" in
-n|--namespace)
if [ -n "$2" ]; then
if [[ -n "$2" ]]; then
NAMESPACE="$2"
else
echo "-n or --namespace requires a value."
Expand All @@ -43,6 +44,16 @@ function parse_arguments {
shift 2
continue
;;
-s|--service)
if [[ -n "$2" ]]; then
SERVICE="$2"
else
echo "-s or --service requires a value."
exit 1
fi
shift 2
continue
;;
-p|--in-pod)
export IN_POD=true
shift 1
Expand All @@ -67,13 +78,13 @@ function parse_arguments {
done
}

# Set the namespace to "sparkoperator" by default if not provided
# Set the namespace to "sparkoperator" by default if not provided.
# Set the webhook service name to "spark-webhook" by default if not provided.
IN_POD=false
SERVICE="spark-webhook"
NAMESPACE="spark-operator"
parse_arguments "$@"


CN_BASE="spark-webhook"
TMP_DIR="/tmp/spark-pod-webhook-certs"

echo "Generating certs for the Spark pod admission webhook in ${TMP_DIR}."
Expand All @@ -90,27 +101,29 @@ extendedKeyUsage = clientAuth, serverAuth
EOF

# Create a certificate authority.
touch ${TMP_DIR}/.rnd
export RANDFILE=${TMP_DIR}/.rnd
openssl genrsa -out ${TMP_DIR}/ca-key.pem 2048
openssl req -x509 -new -nodes -key ${TMP_DIR}/ca-key.pem -days 100000 -out ${TMP_DIR}/ca-cert.pem -subj "/CN=${CN_BASE}_ca"
openssl req -x509 -new -nodes -key ${TMP_DIR}/ca-key.pem -days 100000 -out ${TMP_DIR}/ca-cert.pem -subj "/CN=${SERVICE}_ca"

# Create a server certificate.
openssl genrsa -out ${TMP_DIR}/server-key.pem 2048
# Note the CN is the DNS name of the service of the webhook.
openssl req -new -key ${TMP_DIR}/server-key.pem -out ${TMP_DIR}/server.csr -subj "/CN=spark-webhook.${NAMESPACE}.svc" -config ${TMP_DIR}/server.conf
openssl req -new -key ${TMP_DIR}/server-key.pem -out ${TMP_DIR}/server.csr -subj "/CN=${SERVICE}.${NAMESPACE}.svc" -config ${TMP_DIR}/server.conf
openssl x509 -req -in ${TMP_DIR}/server.csr -CA ${TMP_DIR}/ca-cert.pem -CAkey ${TMP_DIR}/ca-key.pem -CAcreateserial -out ${TMP_DIR}/server-cert.pem -days 100000 -extensions v3_req -extfile ${TMP_DIR}/server.conf

if [ "$IN_POD" == "true" ]; then
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
if [[ "$IN_POD" == "true" ]]; then
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

# Base64 encode secrets and then remove the trailing newline to avoid issues in the curl command
ca_cert=$(cat ${TMP_DIR}/ca-cert.pem | base64 | tr -d '\n')
ca_key=$(cat ${TMP_DIR}/ca-key.pem | base64 | tr -d '\n')
server_cert=$(cat ${TMP_DIR}/server-cert.pem | base64 | tr -d '\n')
server_key=$(cat ${TMP_DIR}/server-key.pem | base64 | tr -d '\n')
# Base64 encode secrets and then remove the trailing newline to avoid issues in the curl command
ca_cert=$(cat ${TMP_DIR}/ca-cert.pem | base64 | tr -d '\n')
ca_key=$(cat ${TMP_DIR}/ca-key.pem | base64 | tr -d '\n')
server_cert=$(cat ${TMP_DIR}/server-cert.pem | base64 | tr -d '\n')
server_key=$(cat ${TMP_DIR}/server-key.pem | base64 | tr -d '\n')

# Create the secret resource
echo "Creating a secret for the certificate and keys"
STATUS=$(curl -ik \
# Create the secret resource
echo "Creating a secret for the certificate and keys"
STATUS=$(curl -ik \
-o ${TMP_DIR}/output \
-w "%{http_code}" \
-X POST \
Expand All @@ -133,22 +146,22 @@ if [ "$IN_POD" == "true" ]; then
}' \
https://kubernetes.default.svc/api/v1/namespaces/${NAMESPACE}/secrets)

cat ${TMP_DIR}/output
cat ${TMP_DIR}/output

case "$STATUS" in
201)
printf "\nSuccess - secret created.\n"
;;
409)
printf "\nSuccess - secret already exists.\n"
;;
*)
printf "\nFailed creating secret.\n"
exit 1
;;
esac
case "$STATUS" in
201)
printf "\nSuccess - secret created.\n"
;;
409)
printf "\nSuccess - secret already exists.\n"
;;
*)
printf "\nFailed creating secret.\n"
exit 1
;;
esac
else
kubectl create secret --namespace=${NAMESPACE} generic spark-webhook-certs --from-file=${TMP_DIR}/ca-key.pem --from-file=${TMP_DIR}/ca-cert.pem --from-file=${TMP_DIR}/server-key.pem --from-file=${TMP_DIR}/server-cert.pem
kubectl create secret --namespace=${NAMESPACE} generic spark-webhook-certs --from-file=${TMP_DIR}/ca-key.pem --from-file=${TMP_DIR}/ca-cert.pem --from-file=${TMP_DIR}/server-key.pem --from-file=${TMP_DIR}/server-cert.pem
fi

# Clean up after we're done.
Expand Down
5 changes: 3 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ var (
resyncInterval = flag.Int("resync-interval", 30, "Informer resync interval in seconds.")
namespace = flag.String("namespace", apiv1.NamespaceAll, "The Kubernetes namespace to manage. Will manage custom resource objects of the managed CRD types for the whole cluster if unset.")
enableWebhook = flag.Bool("enable-webhook", false, "Whether to enable the mutating admission webhook for admitting and patching Spark pods.")
webhookConfigName = flag.String("webhook-config-name", "spark-webhook-config", "The name of the MutatingWebhookConfiguration object to create.")
webhookCertDir = flag.String("webhook-cert-dir", "/etc/webhook-certs", "The directory where x509 certificate and key files are stored.")
webhookSvcNamespace = flag.String("webhook-svc-namespace", "spark-operator", "The namespace of the Service for the webhook server.")
webhookSvcName = flag.String("webhook-svc-name", "spark-webhook", "The name of the Service for the webhook server.")
Expand Down Expand Up @@ -167,7 +168,7 @@ func main() {
if err != nil {
glog.Fatal(err)
}
if err = hook.Start(); err != nil {
if err = hook.Start(*webhookConfigName); err != nil {
glog.Fatal(err)
}
}
Expand All @@ -182,7 +183,7 @@ func main() {
applicationController.Stop()
scheduledApplicationController.Stop()
if *enableWebhook {
if err := hook.Stop(); err != nil {
if err := hook.Stop(*webhookConfigName); err != nil {
glog.Fatal(err)
}
}
Expand Down
13 changes: 6 additions & 7 deletions pkg/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import (
)

const (
webhookConfigName = "spark-webhook-config"
webhookName = "webhook.sparkoperator.k8s.io"
sparkRoleLabel = "spark-role"
sparkDriverRole = "driver"
Expand Down Expand Up @@ -91,20 +90,20 @@ func New(
}

// Start starts the admission webhook server and registers itself to the API server.
func (wh *WebHook) Start() error {
func (wh *WebHook) Start(webhookConfigName string) error {
go func() {
glog.Info("Starting the Spark pod admission webhook server")
if err := wh.server.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
glog.Errorf("error while serving the Spark pod admission webhook: %v\n", err)
}
}()

return wh.selfRegistration()
return wh.selfRegistration(webhookConfigName)
}

// Stop deregisters itself with the API server and stops the admission webhook server.
func (wh *WebHook) Stop() error {
if err := wh.selfDeregistration(); err != nil {
func (wh *WebHook) Stop(webhookConfigName string) error {
if err := wh.selfDeregistration(webhookConfigName); err != nil {
return err
}

Expand Down Expand Up @@ -169,7 +168,7 @@ func (wh *WebHook) serve(w http.ResponseWriter, r *http.Request) {
}
}

func (wh *WebHook) selfRegistration() error {
func (wh *WebHook) selfRegistration(webhookConfigName string) error {
client := wh.clientset.AdmissionregistrationV1beta1().MutatingWebhookConfigurations()
existing, getErr := client.Get(webhookConfigName, metav1.GetOptions{})
if getErr != nil && !errors.IsNotFound(getErr) {
Expand Down Expand Up @@ -227,7 +226,7 @@ func (wh *WebHook) selfRegistration() error {
return nil
}

func (wh *WebHook) selfDeregistration() error {
func (wh *WebHook) selfDeregistration(webhookConfigName string) error {
client := wh.clientset.AdmissionregistrationV1beta1().MutatingWebhookConfigurations()
return client.Delete(webhookConfigName, metav1.NewDeleteOptions(0))
}
Expand Down