Add secrets support

Adds secrets support and binding of secrets at runtime to
functions. Files are written in plain-text to a 0644 permission
folder which can only be read by root and the containers
requesting the secret through the OpenFaaS API.

Tested by deploying an alpine function using "cat" as its
fprocess.

Happy to revisit at a later date and look into encryption at
rest. This should be on-par with using Kubernetes in its
default unencrypted state.

Fixes: #29

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
This commit is contained in:
Alex Ellis (OpenFaaS Ltd)
2020-01-27 19:03:47 +00:00
committed by Alex Ellis
parent 7c166979c9
commit 5c48ac1a70
5 changed files with 150 additions and 8 deletions

View File

@ -22,7 +22,7 @@ import (
"github.com/pkg/errors"
)
func MakeDeployHandler(client *containerd.Client, cni gocni.CNI) func(w http.ResponseWriter, r *http.Request) {
func MakeDeployHandler(client *containerd.Client, cni gocni.CNI, secretMountPath string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
@ -45,11 +45,15 @@ func MakeDeployHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
return
}
name := req.Service
err = validateSecrets(secretMountPath, req.Secrets)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
name := req.Service
ctx := namespaces.WithNamespace(context.Background(), FunctionNamespace)
deployErr := deploy(ctx, req, client, cni)
deployErr := deploy(ctx, req, client, cni, secretMountPath)
if deployErr != nil {
log.Printf("[Deploy] error deploying %s, error: %s\n", name, deployErr)
http.Error(w, deployErr.Error(), http.StatusBadRequest)
@ -58,7 +62,7 @@ func MakeDeployHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
}
}
func deploy(ctx context.Context, req types.FunctionDeployment, client *containerd.Client, cni gocni.CNI) error {
func deploy(ctx context.Context, req types.FunctionDeployment, client *containerd.Client, cni gocni.CNI, secretMountPath string) error {
imgRef := "docker.io/" + req.Image
if strings.Index(req.Image, ":") == -1 {
@ -81,6 +85,15 @@ func deploy(ctx context.Context, req types.FunctionDeployment, client *container
envs := prepareEnv(req.EnvProcess, req.EnvVars)
mounts := getMounts()
for _, secret := range req.Secrets {
mounts = append(mounts, specs.Mount{
Destination: path.Join("/var/openfaas/secrets", secret),
Type: "bind",
Source: path.Join(secretMountPath, secret),
Options: []string{"rbind", "ro"},
})
}
name := req.Service
container, err := client.NewContainer(
@ -177,3 +190,12 @@ func getMounts() []specs.Mount {
})
return mounts
}
func validateSecrets(secretMountPath string, secrets []string) error {
for _, secret := range secrets {
if _, err := os.Stat(path.Join(secretMountPath, secret)); err != nil {
return fmt.Errorf("unable to find secret: %s", secret)
}
}
return nil
}