kata-runtime: add set policy function to kata-runtime

logging/debugging information might probably be disabled in production
due to security consideration, but we'd better provide an approach for
customer to get logging information during runtime, this PR implement
setpolicy function in kata-runtime tools, although it can set whole policy
other than logging.
setpolicy would evokes remote attestation, which means before setting
policy during runtime, user has to reconfigure new policy hash in KBS/AS.

usage:  kata-runtime policy set policy.rego --sandbox-id XXXXXXXX

Fixes: #8797

Signed-off-by: Linda Yu <linda.yu@intel.com>
This commit is contained in:
Linda Yu 2023-12-08 15:29:25 +08:00
parent 73a8b61c2e
commit eda419cb03
6 changed files with 112 additions and 0 deletions

View File

@ -0,0 +1,73 @@
// Copyright (c) 2023 Intel Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"fmt"
"os"
containerdshim "github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2"
"github.com/kata-containers/kata-containers/src/runtime/pkg/katautils"
"github.com/kata-containers/kata-containers/src/runtime/pkg/utils/shimclient"
"github.com/urfave/cli"
)
var policySubCmds = []cli.Command{
setPolicyCommand,
}
var kataPolicyCommand = cli.Command{
Name: "policy",
Usage: "set policy within the Kata Containers guest",
Subcommands: policySubCmds,
Action: func(context *cli.Context) {
cli.ShowSubcommandHelp(context)
},
}
var setPolicyCommand = cli.Command{
Name: "set",
Usage: "set policy in a specifc Kata Containers guest based on file",
Flags: []cli.Flag{
cli.StringFlag{
Name: "sandbox-id",
Usage: "the target sandbox for setting the policy",
Required: true,
Destination: &sandboxID,
},
},
Action: func(c *cli.Context) error {
policyFile := c.Args().Get(0)
// verify sandbox exists:
if err := katautils.VerifyContainerID(sandboxID); err != nil {
return err
}
// verify policy were provided:
if policyFile == "" {
return fmt.Errorf("policy file not provided")
}
if !katautils.FileExists(policyFile) {
return fmt.Errorf("policy file does not exist: %s", policyFile)
}
// Read file into buffer, and make request to the appropriate shim
buf, err := os.ReadFile(policyFile)
if err != nil {
return err
}
url := containerdshim.PolicyUrl
if err = shimclient.DoPut(sandboxID, defaultTimeout, url, "application/octet-stream", buf); err != nil {
return fmt.Errorf("Error observed when making policy-set request(%s): %s", policyFile, err)
}
return nil
},
}

View File

@ -126,6 +126,7 @@ var runtimeCommands = []cli.Command{
factoryCLICommand,
kataVolumeCommand,
kataIPTablesCommand,
kataPolicyCommand,
}
// runtimeBeforeSubcommands is the function to run before command-line

View File

@ -38,6 +38,7 @@ const (
DirectVolumeStatUrl = "/direct-volume/stats"
DirectVolumeResizeUrl = "/direct-volume/resize"
IPTablesUrl = "/iptables"
PolicyUrl = "/policy"
IP6TablesUrl = "/ip6tables"
MetricsUrl = "/metrics"
)
@ -199,6 +200,32 @@ func (s *service) serveVolumeResize(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(""))
}
func (s *service) policyHandler(w http.ResponseWriter, r *http.Request) {
logger := shimMgtLog.WithFields(logrus.Fields{"handler": "policy"})
switch r.Method {
case http.MethodPut:
body, err := io.ReadAll(r.Body)
if err != nil {
logger.WithError(err).Error("failed to read request body")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
if err = s.sandbox.SetPolicy(context.Background(), string(body)); err != nil {
logger.WithError(err).Error("failed to set policy")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
}
w.Write([]byte(""))
default:
w.WriteHeader(http.StatusNotImplemented)
return
}
}
func (s *service) ip6TablesHandler(w http.ResponseWriter, r *http.Request) {
s.genericIPTablesHandler(w, r, true)
}
@ -266,6 +293,7 @@ func (s *service) startManagementServer(ctx context.Context, ociSpec *specs.Spec
m.Handle(DirectVolumeStatUrl, http.HandlerFunc(s.serveVolumeStats))
m.Handle(DirectVolumeResizeUrl, http.HandlerFunc(s.serveVolumeResize))
m.Handle(IPTablesUrl, http.HandlerFunc(s.ipTablesHandler))
m.Handle(PolicyUrl, http.HandlerFunc(s.policyHandler))
m.Handle(IP6TablesUrl, http.HandlerFunc(s.ip6TablesHandler))
s.mountPprofHandle(m, ociSpec)

View File

@ -82,6 +82,7 @@ type VCSandbox interface {
GetIPTables(ctx context.Context, isIPv6 bool) ([]byte, error)
SetIPTables(ctx context.Context, isIPv6 bool, data []byte) error
SetPolicy(ctx context.Context, policy string) error
}
// VCContainer is the Container interface

View File

@ -269,3 +269,7 @@ func (s *Sandbox) GetIPTables(ctx context.Context, isIPv6 bool) ([]byte, error)
func (s *Sandbox) SetIPTables(ctx context.Context, isIPv6 bool, data []byte) error {
return nil
}
func (s *Sandbox) SetPolicy(ctx context.Context, policy string) error {
return nil
}

View File

@ -2607,6 +2607,11 @@ func (s *Sandbox) SetIPTables(ctx context.Context, isIPv6 bool, data []byte) err
return s.agent.setIPTables(ctx, isIPv6, data)
}
// SetPolicy will set the policy in the guest
func (s *Sandbox) SetPolicy(ctx context.Context, policy string) error {
return s.agent.setPolicy(ctx, policy)
}
// GuestVolumeStats return the filesystem stat of a given volume in the guest.
func (s *Sandbox) GuestVolumeStats(ctx context.Context, volumePath string) ([]byte, error) {
guestMountPath, err := s.guestMountPath(volumePath)