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

go/oasis-node: allow km to have private peers #4821

Merged
merged 2 commits into from
Jun 28, 2022
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
1 change: 1 addition & 0 deletions .changelog/4821.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/oasis-node: allow km to have private peers
11 changes: 11 additions & 0 deletions go/oasis-test-runner/oasis/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,17 @@ func (args *argBuilder) workerKeymanagerMayGenerate() *argBuilder {
return args
}

func (args *argBuilder) workerKeymanagerPrivatePeerPubKeys(peerPKs []string) *argBuilder {
for _, pk := range peerPKs {
args.vec = append(args.vec, Argument{
Name: keymanager.CfgPrivatePeerPubKeys,
Values: []string{pk},
MultiValued: true,
})
}
return args
}

func (args *argBuilder) workerSentryEnabled() *argBuilder {
args.vec = append(args.vec, Argument{Name: workerSentry.CfgEnabled})
return args
Expand Down
10 changes: 10 additions & 0 deletions go/oasis-test-runner/oasis/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import (
runtimeRegistry "github.com/oasisprotocol/oasis-core/go/runtime/registry"
)

const (
clientIdentitySeedTemplate = "ekiden node client %d"
)

// Client is an Oasis client node.
type Client struct {
*Node
Expand Down Expand Up @@ -70,6 +74,12 @@ func (net *Network) NewClient(cfg *ClientCfg) (*Client, error) {
cfg.RuntimeProvisioner = runtimeRegistry.RuntimeProvisionerUnconfined
}

// Pre-provision the node identity so that we can identify the entity.
err = host.setProvisionedIdentity(false, fmt.Sprintf(clientIdentitySeedTemplate, len(net.clients)))
if err != nil {
return nil, fmt.Errorf("oasis/client: failed to provision node identity: %w", err)
}

client := &Client{
Node: host,
runtimes: cfg.Runtimes,
Expand Down
3 changes: 3 additions & 0 deletions go/oasis-test-runner/oasis/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ type KeymanagerFixture struct {
CrashPointsProbability float64 `json:"crash_points_probability,omitempty"`

LogWatcherHandlerFactories []log.WatcherHandlerFactory `json:"-"`

PrivatePeerPubKeys []string `json:"private_peer_pub_keys,omitempty"`
}

// Create instantiates the key manager described by the fixture.
Expand Down Expand Up @@ -356,6 +358,7 @@ func (f *KeymanagerFixture) Create(net *Network) (*Keymanager, error) {
Runtime: runtime,
Policy: policy,
SentryIndices: f.Sentries,
PrivatePeerPubKeys: f.PrivatePeerPubKeys,
})
}

Expand Down
2 changes: 1 addition & 1 deletion go/oasis-test-runner/oasis/ias.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (ias *iasProxy) AddArgs(args *argBuilder) error {

// XXX: IAS proxy is started before the validators. Pregenerate temp validator internal socket path.
if ias.net.cfg.UseShortGrpcSocketPaths && ias.net.validators[0].customGrpcSocketPath == "" {
ias.net.validators[0].customGrpcSocketPath = ias.net.generateTempSocketPath()
ias.net.validators[0].customGrpcSocketPath = ias.net.generateTempSocketPath("ias")
}
args.internalSocketAddress(ias.net.validators[0].SocketPath())

Expand Down
7 changes: 7 additions & 0 deletions go/oasis-test-runner/oasis/keymanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ type Keymanager struct { // nolint: maligned
p2pPort uint16

mayGenerate bool

privatePeerPubKeys []string
}

// KeymanagerCfg is the Oasis key manager provisioning configuration.
Expand All @@ -173,6 +175,9 @@ type KeymanagerCfg struct {
Runtime *Runtime
Policy *KeymanagerPolicy
RuntimeProvisioner string

// PrivatePeerPubKeys is a list of base64-encoded libp2p public keys of peers who may call non-public methods.
PrivatePeerPubKeys []string
}

// IdentityKeyPath returns the paths to the node's identity key.
Expand Down Expand Up @@ -270,6 +275,7 @@ func (km *Keymanager) AddArgs(args *argBuilder) error {
runtimeSGXLoader(km.net.cfg.RuntimeSGXLoaderBinary).
runtimePath(km.runtime).
workerKeymanagerRuntimeID(km.runtime.ID()).
workerKeymanagerPrivatePeerPubKeys(km.privatePeerPubKeys).
configureDebugCrashPoints(km.crashPointsProbability).
tendermintSupplementarySanity(km.supplementarySanityInterval).
appendNetwork(km.net).
Expand Down Expand Up @@ -336,6 +342,7 @@ func (net *Network) NewKeymanager(cfg *KeymanagerCfg) (*Keymanager, error) {
workerClientPort: host.getProvisionedPort(nodePortClient),
p2pPort: host.getProvisionedPort(nodePortP2P),
mayGenerate: len(net.keymanagers) == 0,
privatePeerPubKeys: cfg.PrivatePeerPubKeys,
}

net.keymanagers = append(net.keymanagers, km)
Expand Down
8 changes: 4 additions & 4 deletions go/oasis-test-runner/oasis/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,8 @@ func GenerateDeterministicNodeKeys(dir *env.Dir, rawSeed string, roles []signatu
//
// This function is used to obtain shorter socket path than the one in datadir since that one might
// be too long for unix socket path.
func (net *Network) generateTempSocketPath() string {
f, err := ioutil.TempFile(env.GetRootDir().String(), "internal-*.sock")
func (net *Network) generateTempSocketPath(prefix string) string {
f, err := ioutil.TempFile(env.GetRootDir().String(), fmt.Sprintf("%s-internal-*.sock", prefix))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice for debugging

if err != nil {
return ""
}
Expand Down Expand Up @@ -616,7 +616,7 @@ func (net *Network) startOasisNode(
if net.cfg.UseShortGrpcSocketPaths {
// Keep the socket, if it was already generated!
if node.customGrpcSocketPath == "" {
node.customGrpcSocketPath = net.generateTempSocketPath()
node.customGrpcSocketPath = net.generateTempSocketPath(node.Name)
}
extraArgs = extraArgs.debugDontBlameOasis()
extraArgs = extraArgs.grpcDebugGrpcInternalSocketPath(node.customGrpcSocketPath)
Expand Down Expand Up @@ -865,7 +865,7 @@ func (net *Network) GetCLIConfig() cli.Config {
if len(net.Validators()) > 0 {
val := net.Validators()[0]
if net.cfg.UseShortGrpcSocketPaths && val.customGrpcSocketPath == "" {
val.customGrpcSocketPath = net.generateTempSocketPath()
val.customGrpcSocketPath = net.generateTempSocketPath(val.Node.Name)
}
cfg.NodeSocketPath = val.SocketPath()
}
Expand Down
7 changes: 5 additions & 2 deletions go/oasis-test-runner/oasis/oasis.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,11 @@ func (n *Node) setProvisionedIdentity(persistTLS bool, seed string) error {
return err
}

if err := n.entity.addNode(nodeSigner); err != nil {
return err
if n.entity != nil {
// Client nodes may need a provisioned identity. They never need an entity, however.
if err := n.entity.addNode(nodeSigner); err != nil {
return err
}
}

n.nodeSigner = nodeSigner
Expand Down
23 changes: 23 additions & 0 deletions go/worker/keymanager/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ package keymanager

import (
"context"
"encoding/base64"
"fmt"

core "github.com/libp2p/go-libp2p-core"
flag "github.com/spf13/pflag"
"github.com/spf13/viper"

"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/logging"
"github.com/oasisprotocol/oasis-core/go/common/node"
ias "github.com/oasisprotocol/oasis-core/go/ias/api"
"github.com/oasisprotocol/oasis-core/go/keymanager/api"
"github.com/oasisprotocol/oasis-core/go/runtime/localstorage"
runtimeRegistry "github.com/oasisprotocol/oasis-core/go/runtime/registry"
workerCommon "github.com/oasisprotocol/oasis-core/go/worker/common"
p2pAPI "github.com/oasisprotocol/oasis-core/go/worker/common/p2p/api"
"github.com/oasisprotocol/oasis-core/go/worker/keymanager/p2p"
"github.com/oasisprotocol/oasis-core/go/worker/registration"
)
Expand All @@ -26,6 +29,8 @@ const (
CfgRuntimeID = "worker.keymanager.runtime.id"
// CfgMayGenerate allows the enclave to generate a master secret.
CfgMayGenerate = "worker.keymanager.may_generate"
// CfgPrivatePeerPks allows adding manual, unadvertised peers that can call protected methods.
CfgPrivatePeerPubKeys = "worker.keymanager.private_peer_pub_keys"
)

// Flags has the configuration flags.
Expand Down Expand Up @@ -59,6 +64,7 @@ func New(
initCh: make(chan struct{}),
initTickerCh: nil,
accessList: make(map[core.PeerID]map[common.Namespace]struct{}),
privatePeers: make(map[core.PeerID]struct{}),
accessListByRuntime: make(map[common.Namespace][]core.PeerID),
commonWorker: commonWorker,
backend: backend,
Expand All @@ -70,6 +76,22 @@ func New(
return w, nil
}

for _, b64pk := range viper.GetStringSlice(CfgPrivatePeerPubKeys) {
pkBytes, err := base64.StdEncoding.DecodeString(b64pk)
if err != nil {
return nil, fmt.Errorf("oasis/keymanager: `%s` is not a base64-encoded public key (%w)", b64pk, err)
}
var pk signature.PublicKey
if err = pk.UnmarshalBinary(pkBytes); err != nil {
return nil, fmt.Errorf("oasis/keymanager: `%s` is not a public key (%w)", b64pk, err)
}
peerID, err := p2pAPI.PublicKeyToPeerID(pk)
if err != nil {
return nil, fmt.Errorf("oasis/keymanager: `%s` can not be converted to a peer id (%w)", b64pk, err)
}
w.privatePeers[peerID] = struct{}{}
}

var runtimeID common.Namespace
if err := runtimeID.UnmarshalHex(viper.GetString(CfgRuntimeID)); err != nil {
return nil, fmt.Errorf("worker/keymanager: failed to parse runtime ID: %w", err)
Expand Down Expand Up @@ -115,6 +137,7 @@ func New(
func init() {
Flags.String(CfgRuntimeID, "", "Key manager Runtime ID")
Flags.Bool(CfgMayGenerate, false, "Key manager may generate new master secret")
Flags.StringSlice(CfgPrivatePeerPubKeys, []string{}, "b64-encoded public keys of unadvertised peers that may call protected methods")

_ = viper.BindPFlags(Flags)
}
15 changes: 9 additions & 6 deletions go/worker/keymanager/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type Worker struct { // nolint: maligned

accessList map[core.PeerID]map[common.Namespace]struct{}
accessListByRuntime map[common.Namespace][]core.PeerID
privatePeers map[core.PeerID]struct{}

commonWorker *workerCommon.Worker
roleProvider registration.RoleProvider
Expand Down Expand Up @@ -175,12 +176,14 @@ func (w *Worker) CallEnclave(ctx context.Context, data []byte) ([]byte, error) {
case getPublicKeyRequestMethod:
// Anyone can get public keys.
default:
// Defer to access control to check the policy.
w.RLock()
_, allowed := w.accessList[peerID]
w.RUnlock()
if !allowed {
return nil, fmt.Errorf("not authorized")
if _, privatePeered := w.privatePeers[peerID]; !privatePeered {
// Defer to access control to check the policy.
w.RLock()
_, allowed := w.accessList[peerID]
w.RUnlock()
if !allowed {
return nil, fmt.Errorf("not authorized")
}
}
}

Expand Down