blob: b681abf00a28e6ca8f02ce7fccfa740a2f79210a [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The following enables go generate to generate the doc.go file.
//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
package main
import (
"encoding/base64"
"io/ioutil"
"os"
"strings"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/security"
"v.io/v23/vom"
"v.io/x/lib/cmdline"
lsecurity "v.io/x/ref/lib/security"
"v.io/x/ref/lib/signals"
"v.io/x/ref/lib/v23cmd"
"v.io/x/ref/services/agent/internal/ipc"
"v.io/x/ref/services/agent/internal/server"
"v.io/x/ref/services/cluster"
_ "v.io/x/ref/runtime/factories/roaming"
)
var (
clusterAgent string
socketPath string
secretKeyFile string
rootBlessings string
)
func main() {
cmdPodAgentD.Flags.StringVar(&clusterAgent, "agent", "", "The address of the cluster agent.")
cmdPodAgentD.Flags.StringVar(&socketPath, "socket-path", "", "The path of the unix socket to listen on.")
cmdPodAgentD.Flags.StringVar(&secretKeyFile, "secret-key-file", "", "The name of the file that contains the secret key.")
cmdPodAgentD.Flags.StringVar(&rootBlessings, "root-blessings", "", "A comma-separated list of the root blessings to trust, base64-encoded VOM-encoded.")
cmdline.HideGlobalFlagsExcept()
cmdline.Main(cmdPodAgentD)
}
var cmdPodAgentD = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runPodAgentD),
Name: "pod_agentd",
Short: "Holds the principal of a kubernetes pod",
Long: `
Command pod_agentd runs a security agent daemon, which holds a private key in
memory and makes it available to the kubernetes pod in which it is running.
`,
}
func runPodAgentD(ctx *context.T, env *cmdline.Env, args []string) error {
p, err := lsecurity.NewPrincipal()
if err != nil {
return err
}
if ctx, err = v23.WithPrincipal(ctx, p); err != nil {
return err
}
if rootBlessings != "" {
addRoot(ctx, rootBlessings)
}
secret, err := ioutil.ReadFile(secretKeyFile)
if err != nil {
return err
}
// Fetch blessings from cluster agent.
ca := cluster.ClusterAgentClient(clusterAgent)
blessings, err := ca.SeekBlessings(ctx, string(secret))
if err != nil {
return err
}
if err = p.BlessingStore().SetDefault(blessings); err != nil {
return err
}
if _, err = p.BlessingStore().Set(blessings, security.AllPrincipals); err != nil {
return err
}
if err = security.AddToRoots(p, blessings); err != nil {
return err
}
// Run the server.
i := ipc.NewIPC()
defer i.Close()
if err = server.ServeAgent(i, lsecurity.MustForkPrincipal(
p,
lsecurity.ImmutableBlessingStore(p.BlessingStore()),
lsecurity.ImmutableBlessingRoots(p.Roots()))); err != nil {
return err
}
if _, err := os.Stat(socketPath); err == nil {
os.Remove(socketPath)
}
if err = i.Listen(socketPath); err != nil {
return err
}
// Make the socket available to all users so that the application can
// run with a non-root UID.
// The socket's parent directory is mounted only in the containers that
// should have access to it. So, this doesn't change who has access to
// the socket.
if err = os.Chmod(socketPath, 0666); err != nil {
return err
}
<-signals.ShutdownOnSignals(ctx)
return nil
}
func addRoot(ctx *context.T, flagRoots string) {
p := v23.GetPrincipal(ctx)
for _, b64 := range strings.Split(flagRoots, ",") {
// We use URLEncoding to be compatible with the principal
// command.
vomBlessings, err := base64.URLEncoding.DecodeString(b64)
if err != nil {
ctx.Fatalf("unable to decode the base64 blessing roots: %v", err)
}
var blessings security.Blessings
if err := vom.Decode(vomBlessings, &blessings); err != nil {
ctx.Fatalf("unable to decode the vom blessing roots: %v", err)
}
if err := security.AddToRoots(p, blessings); err != nil {
ctx.Fatalf("unable to add blessing roots: %v", err)
}
}
}