Skip to content

Commit

Permalink
Adds key creation for http signatures
Browse files Browse the repository at this point in the history
Resolves issue openfaas#1103

Signed-off-by: Edward Wilde <[email protected]>
  • Loading branch information
ewilde committed Feb 24, 2019
1 parent 44f423b commit 78ce56f
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 59 deletions.
177 changes: 119 additions & 58 deletions deploy_stack.sh
Original file line number Diff line number Diff line change
@@ -1,66 +1,127 @@
#!/bin/sh
#!/usr/bin/env bash
set -e

if ! [ -x "$(command -v docker)" ]; then
echo 'Unable to find docker command, please install Docker (https://www.docker.com/) and retry' >&2
exit 1
fi
CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"
PARTY_POPPER="\xF0\x9F\x8E\x89"
DEBUG_LOG=${DEBUG_LOG:=0}
function debug() {
if [[ ${DEBUG_LOG} = "1" ]]; then
echo -e "$*";
fi
}

export BASIC_AUTH="true"
check_required_software() {
echo -en " Required software check"

sha_cmd="shasum -a 256"
if ! command -v shasum >/dev/null; then
sha_cmd="sha256sum"
fi
if ! [[ -x "$(command -v docker)" ]]; then
echo 'Unable to find docker command, please install Docker (https://www.docker.com/) and retry' >&2
exit 1
fi

while [ ! $# -eq 0 ]
echo -e "\r${CHECK_MARK} Required software check"
}

setup_http_signature() {
echo -en " Http encryption settings"

rm signing.key > /dev/null 2>&1 || true && rm signing.key.pub > /dev/null 2>&1 || true
docker secret rm http-signing-private-key > /dev/null 2>&1 || true
docker secret rm http-signing-public-key > /dev/null 2>&1 || true

ssh-keygen -t rsa -b 2048 -N "" -m PEM -f signing.key > /dev/null 2>&1
openssl rsa -in ./signing.key -pubout -outform PEM -out signing.key.pub > /dev/null 2>&1

cat signing.key | docker secret create http-signing-private-key - > /dev/null 2>&1 || true
cat signing.key.pub | docker secret create http-signing-public-key - > /dev/null 2>&1 || true

rm signing.key || true && rm signing.key.pub || true
echo -e "\r${CHECK_MARK} Http encryption settings"
}

setup_basic_auth() {
export BASIC_AUTH="true"
sha_cmd="shasum -a 256"
if ! command -v shasum >/dev/null; then
sha_cmd="sha256sum"
fi

# Secrets should be created even if basic-auth is disabled.
if (echo "admin" | docker secret create basic-auth-user - > /dev/null 2>&1)
then
debug "[Credentials]\n\tusername: admin created"
fi

secret=$(head -c 16 /dev/urandom| $sha_cmd | cut -d " " -f 1)
if (echo "$secret" | docker secret create basic-auth-password - > /dev/null 2>&1)
then
echo -e "[Credentials]\n\tusername: admin \n\tpassword: ${secret}\n\techo -n \"${secret}\" | faas-cli login --username=admin --password-stdin"
else
debug "[Credentials]\n\talready exist, not creating"
fi

if [[ ${BASIC_AUTH} = "true" ]];
then
debug "\tenabling basic authentication for gateway.."
debug ""
else
debug "\tdisabling basic authentication for gateway.."
debug ""
fi

echo -e "\r${CHECK_MARK} Basic authentication settings"
}

deploy_docker_stack() {
arch=$(uname -m)
case "$arch" in

"armv7l") echo -en " Deploying OpenFaaS core services for ARM"
composefile="docker-compose.armhf.yml"
;;
"aarch64") echo -en " Deploying OpenFaaS core services for ARM64"
composefile="docker-compose.arm64.yml"
;;
*) echo -en " Deploying OpenFaaS core services"
composefile="docker-compose.yml"
;;
esac

docker stack deploy func --compose-file ${composefile} > /dev/null
echo -e "\r${CHECK_MARK} Deploying OpenFaaS core services"
}

main() {
check_required_software
setup_basic_auth
setup_http_signature
deploy_docker_stack
echo -e ${PARTY_POPPER}OpenFaaS docker swarm setup complete
}

POSITIONAL=()
while [[ $# -gt 0 ]]
do
case "$1" in
--no-auth | -n)
export BASIC_AUTH="false"
;;
--help | -h)
echo "Usage: \n [default]\tdeploy the OpenFaaS core services\n --no-auth [-n]\tdisable basic authentication.\n --help\tdisplays this screen"
exit
;;
esac
shift
done
key="$1"

# Secrets should be created even if basic-auth is disabled.
echo "Attempting to create credentials for gateway.."
echo "admin" | docker secret create basic-auth-user -
secret=$(head -c 16 /dev/urandom| $sha_cmd | cut -d " " -f 1)
echo "$secret" | docker secret create basic-auth-password -
if [ $? = 0 ];
then
echo "[Credentials]\n username: admin \n password: $secret\n echo -n "$secret" | faas-cli login --username=admin --password-stdin"
else
echo "[Credentials]\n already exist, not creating"
fi

if [ $BASIC_AUTH = "true" ];
then
echo ""
echo "Enabling basic authentication for gateway.."
echo ""
else
echo ""
echo "Disabling basic authentication for gateway.."
echo ""
fi

arch=$(uname -m)
case "$arch" in

"armv7l") echo "Deploying OpenFaaS core services for ARM"
composefile="docker-compose.armhf.yml"
;;
"aarch64") echo "Deploying OpenFaaS core services for ARM64"
composefile="docker-compose.arm64.yml"
;;
*) echo "Deploying OpenFaaS core services"
composefile="docker-compose.yml"
;;
case $key in
--no-auth | -n)
export BASIC_AUTH="false"
shift
;;
--debug | -d)
DEBUG_LOG="1"
shift
;;
--help | -h)
echo -e "Usage:
[default] deploy the OpenFaaS core services
--no-auth [-n] disable basic authentication.
--help displays this screen
--debug [-d] enable debug logging"
exit
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters

docker stack deploy func --compose-file $composefile
main
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ services:
secrets:
- basic-auth-user
- basic-auth-password
- http-signing-public-key

# Docker Swarm provider
faas-swarm:
Expand Down Expand Up @@ -198,3 +199,5 @@ secrets:
external: true
basic-auth-password:
external: true
http-signing-public-key:
external: true
69 changes: 69 additions & 0 deletions gateway/handlers/certificates_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package handlers

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"

"github.com/gorilla/mux"
)

var keyMap = map[string]string{
"callback": "http-signing-public-key",
}

type KeyType struct {
Id string `json:"id"`
PEM string `json:"pem"`
}

func MakeCertificatesHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
keyID := vars["id"]
secretKey, ok := keyMap[keyID]
if !ok {
w.WriteHeader(http.StatusNotFound)
message := fmt.Sprintf("Unable to find certificate %s.", keyID)
w.Write([]byte(message))
log.Println(message)
return
}

if _, err := os.Stat(fmt.Sprintf("/run/secrets/%s", secretKey)); os.IsNotExist(err) {
w.WriteHeader(http.StatusNotFound)
message := fmt.Sprintf("Unable to find secret for key %s.", keyID)
w.Write([]byte(message))
log.Println(message)
return
}

signingKey, err := ioutil.ReadFile(fmt.Sprintf("/run/secrets/%s", secretKey))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
message := fmt.Sprintf("error reading secret for key %s. %v", keyID, err)
w.Write([]byte(message))
log.Println(message)
}

key := &KeyType{
Id: secretKey,
PEM: string(signingKey),
}

bytesOut, marshalErr := json.Marshal(key)
if marshalErr != nil {
w.WriteHeader(http.StatusInternalServerError)
message := fmt.Sprintf("error marshalling json for key %s. %v", keyID, err)
w.Write([]byte(message))
log.Println(message)
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(bytesOut)
}
}
2 changes: 1 addition & 1 deletion gateway/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ func main() {
metricsHandler := metrics.PrometheusHandler()
r.Handle("/metrics", metricsHandler)
r.HandleFunc("/healthz", handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)).Methods(http.MethodGet)

r.Handle("/certificates/{id}", handlers.MakeCertificatesHandler())
r.Handle("/", http.RedirectHandler("/ui/", http.StatusMovedPermanently)).Methods(http.MethodGet)

tcpPort := 8080
Expand Down

0 comments on commit 78ce56f

Please sign in to comment.