mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
AB#2046 : Add option to create SSH users for the first coordinator upon initialization (#133)
* Move `file`, `ssh` and `user` packages to internal * Rename `SSHKey` to `(ssh.)UserKey` * Rename KeyValue / Publickey to PublicKey * Rename SSH key file from "debugd" to "ssh-keys" * Add CreateSSHUsers function to Core * Call CreateSSHUsers users on first control-plane node, when defined in config Tests: * Make StubUserCreator add entries to /etc/passwd * Add NewLinuxUserManagerFake for unit tests * Add unit tests & adjust existing ones to changes
This commit is contained in:
parent
5dc2e71d80
commit
68092f27dd
@ -1,9 +1,9 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -8,10 +8,10 @@ import (
|
||||
"github.com/edgelesssys/constellation/cli/azure"
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/cli/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/gcp"
|
||||
"github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -9,9 +9,9 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/azure"
|
||||
"github.com/edgelesssys/constellation/cli/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/gcp"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -14,16 +14,18 @@ import (
|
||||
"github.com/edgelesssys/constellation/cli/azure"
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/cli/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/gcp"
|
||||
"github.com/edgelesssys/constellation/cli/proto"
|
||||
"github.com/edgelesssys/constellation/cli/status"
|
||||
"github.com/edgelesssys/constellation/cli/vpn"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
coordinatorstate "github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/edgelesssys/constellation/coordinator/util"
|
||||
"github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/kr/text"
|
||||
wgquick "github.com/nmiculinic/wg-quick-go"
|
||||
@ -78,6 +80,8 @@ func initialize(ctx context.Context, cmd *cobra.Command, protCl protoClient, ser
|
||||
return err
|
||||
}
|
||||
|
||||
protoSSHUserKeys := ssh.ToProtoSlice(config.SSHUsers)
|
||||
|
||||
var stat state.ConstellationState
|
||||
err = fileHandler.ReadJSON(constants.StateFilename, &stat)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
@ -129,6 +133,7 @@ func initialize(ctx context.Context, cmd *cobra.Command, protCl protoClient, ser
|
||||
coordinatorPrivIPs: coordinators.PrivateIPs()[1:],
|
||||
autoscalingNodeGroups: autoscalingNodeGroups,
|
||||
cloudServiceAccountURI: serviceAccount,
|
||||
sshUserKeys: protoSSHUserKeys,
|
||||
}
|
||||
result, err := activate(ctx, cmd, protCl, input, validators.V())
|
||||
if err != nil {
|
||||
@ -166,7 +171,7 @@ func activate(ctx context.Context, cmd *cobra.Command, client protoClient, input
|
||||
return activationResult{}, err
|
||||
}
|
||||
|
||||
respCl, err := client.Activate(ctx, input.pubKey, input.masterSecret, input.nodePrivIPs, input.coordinatorPrivIPs, input.autoscalingNodeGroups, input.cloudServiceAccountURI)
|
||||
respCl, err := client.Activate(ctx, input.pubKey, input.masterSecret, input.nodePrivIPs, input.coordinatorPrivIPs, input.autoscalingNodeGroups, input.cloudServiceAccountURI, input.sshUserKeys)
|
||||
if err != nil {
|
||||
return activationResult{}, err
|
||||
}
|
||||
@ -216,6 +221,7 @@ type activationInput struct {
|
||||
coordinatorPrivIPs []string
|
||||
autoscalingNodeGroups []string
|
||||
cloudServiceAccountURI string
|
||||
sshUserKeys []*pubproto.SSHUserKey
|
||||
}
|
||||
|
||||
type activationResult struct {
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/azure"
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/gcp"
|
||||
"github.com/edgelesssys/constellation/cli/qemu"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
wgquick "github.com/nmiculinic/wg-quick-go"
|
||||
"github.com/spf13/afero"
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/proto"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
)
|
||||
|
||||
@ -12,5 +13,5 @@ type protoClient interface {
|
||||
Connect(endpoint string, validators []atls.Validator) error
|
||||
Close() error
|
||||
GetState(ctx context.Context) (state.State, error)
|
||||
Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs, autoscalingNodeGroups []string, cloudServiceAccountURI string) (proto.ActivationResponseClient, error)
|
||||
Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs, autoscalingNodeGroups []string, cloudServiceAccountURI string, sshUsers []*pubproto.SSHUserKey) (proto.ActivationResponseClient, error)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/proto"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
)
|
||||
|
||||
@ -26,6 +27,7 @@ type stubProtoClient struct {
|
||||
activateCoordinatorIPs []string
|
||||
activateAutoscalingNodeGroups []string
|
||||
cloudServiceAccountURI string
|
||||
sshUserKeys []*pubproto.SSHUserKey
|
||||
}
|
||||
|
||||
func (c *stubProtoClient) Connect(_ string, _ []atls.Validator) error {
|
||||
@ -42,13 +44,14 @@ func (c *stubProtoClient) GetState(_ context.Context) (state.State, error) {
|
||||
return c.getStateState, c.getStateErr
|
||||
}
|
||||
|
||||
func (c *stubProtoClient) Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs []string, autoscalingNodeGroups []string, cloudServiceAccountURI string) (proto.ActivationResponseClient, error) {
|
||||
func (c *stubProtoClient) Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs []string, autoscalingNodeGroups []string, cloudServiceAccountURI string, sshUserKeys []*pubproto.SSHUserKey) (proto.ActivationResponseClient, error) {
|
||||
c.activateUserPublicKey = userPublicKey
|
||||
c.activateMasterSecret = masterSecret
|
||||
c.activateNodeIPs = nodeIPs
|
||||
c.activateCoordinatorIPs = coordinatorIPs
|
||||
c.activateAutoscalingNodeGroups = autoscalingNodeGroups
|
||||
c.cloudServiceAccountURI = cloudServiceAccountURI
|
||||
c.sshUserKeys = sshUserKeys
|
||||
|
||||
return c.respClient, c.activateErr
|
||||
}
|
||||
@ -126,7 +129,7 @@ func (c *fakeProtoClient) GetState(_ context.Context) (state.State, error) {
|
||||
return state.IsNode, nil
|
||||
}
|
||||
|
||||
func (c *fakeProtoClient) Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs, autoscalingNodeGroups []string, cloudServiceAccountURI string) (proto.ActivationResponseClient, error) {
|
||||
func (c *fakeProtoClient) Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs, autoscalingNodeGroups []string, cloudServiceAccountURI string, sshUserKeys []*pubproto.SSHUserKey) (proto.ActivationResponseClient, error) {
|
||||
if !c.conn {
|
||||
return nil, errors.New("client is not connected")
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/cli/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/proto"
|
||||
"github.com/edgelesssys/constellation/coordinator/util"
|
||||
"github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
)
|
||||
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/cli/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/proto"
|
||||
"github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
rpcStatus "google.golang.org/grpc/status"
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -73,7 +73,7 @@ func (c *Client) GetState(ctx context.Context) (state.State, error) {
|
||||
// Activate activates the Constellation coordinator via a grpc call.
|
||||
// The handed IP addresses must be the private IP addresses of running AWS or GCP instances,
|
||||
// and the userPublicKey is the VPN key of the users WireGuard interface.
|
||||
func (c *Client) Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs, autoscalingNodeGroups []string, cloudServiceAccountURI string) (ActivationResponseClient, error) {
|
||||
func (c *Client) Activate(ctx context.Context, userPublicKey, masterSecret []byte, nodeIPs, coordinatorIPs, autoscalingNodeGroups []string, cloudServiceAccountURI string, sshUserKeys []*pubproto.SSHUserKey) (ActivationResponseClient, error) {
|
||||
if c.pubapi == nil {
|
||||
return nil, errors.New("client is not connected")
|
||||
}
|
||||
@ -100,6 +100,7 @@ func (c *Client) Activate(ctx context.Context, userPublicKey, masterSecret []byt
|
||||
KeyEncryptionKeyId: "",
|
||||
UseExistingKek: false,
|
||||
CloudServiceAccountUri: cloudServiceAccountURI,
|
||||
SshUserKeys: sshUserKeys,
|
||||
}
|
||||
|
||||
client, err := c.pubapi.ActivateAsCoordinator(ctx, req)
|
||||
|
@ -163,7 +163,7 @@ func TestActivate(t *testing.T) {
|
||||
if tc.pubAPIClient != nil {
|
||||
client.pubapi = tc.pubAPIClient
|
||||
}
|
||||
_, err := client.Activate(context.Background(), []byte(tc.userPublicKey), []byte("Constellation"), tc.ips, nil, nil, "serviceaccount://test")
|
||||
_, err := client.Activate(context.Background(), []byte(tc.userPublicKey), []byte("Constellation"), tc.ips, nil, nil, "serviceaccount://test", nil)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/azure"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/gcp"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/qemu"
|
||||
@ -27,6 +26,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/util"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/grpcutil"
|
||||
"github.com/edgelesssys/constellation/coordinator/wireguard"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/zap"
|
||||
@ -174,5 +174,5 @@ func main() {
|
||||
netDialer := &net.Dialer{}
|
||||
dialer := grpcutil.NewDialer(validator, netDialer)
|
||||
run(issuer, wg, openTPM, util.GetIPAddr, dialer, fileHandler, kube,
|
||||
metadata, cloudControllerManager, cloudNodeManager, autoscaler, encryptedDisk, etcdEndpoint, enforceEtcdTls, bindIP, bindPort, zapLoggerCore)
|
||||
metadata, cloudControllerManager, cloudNodeManager, autoscaler, encryptedDisk, etcdEndpoint, enforceEtcdTls, bindIP, bindPort, zapLoggerCore, fs)
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
@ -17,9 +16,12 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/util/grpcutil"
|
||||
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
||||
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@ -29,6 +31,7 @@ var version = "0.0.0"
|
||||
|
||||
func run(issuer core.QuoteIssuer, vpn core.VPN, openTPM vtpm.TPMOpenFunc, getPublicIPAddr func() (string, error), dialer *grpcutil.Dialer, fileHandler file.Handler,
|
||||
kube core.Cluster, metadata core.ProviderMetadata, cloudControllerManager core.CloudControllerManager, cloudNodeManager core.CloudNodeManager, clusterAutoscaler core.ClusterAutoscaler, encryptedDisk core.EncryptedDisk, etcdEndpoint string, etcdTLS bool, bindIP, bindPort string, zapLoggerCore *zap.Logger,
|
||||
fs afero.Fs,
|
||||
) {
|
||||
defer zapLoggerCore.Sync()
|
||||
zapLoggerCore.Info("starting coordinator", zap.String("version", version))
|
||||
@ -43,7 +46,8 @@ func run(issuer core.QuoteIssuer, vpn core.VPN, openTPM vtpm.TPMOpenFunc, getPub
|
||||
ForceTLS: etcdTLS,
|
||||
Logger: zapLoggerCore.WithOptions(zap.IncreaseLevel(zap.WarnLevel)).Named("etcd"),
|
||||
}
|
||||
core, err := core.NewCore(vpn, kube, metadata, cloudControllerManager, cloudNodeManager, clusterAutoscaler, encryptedDisk, zapLoggerCore, openTPM, etcdStoreFactory, fileHandler)
|
||||
linuxUserManager := user.NewLinuxUserManager(fs)
|
||||
core, err := core.NewCore(vpn, kube, metadata, cloudControllerManager, cloudNodeManager, clusterAutoscaler, encryptedDisk, zapLoggerCore, openTPM, etcdStoreFactory, fileHandler, linuxUserManager)
|
||||
if err != nil {
|
||||
zapLoggerCore.Fatal("failed to create core", zap.Error(err))
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
@ -21,6 +20,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/util/testdialer"
|
||||
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
||||
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -211,7 +212,8 @@ func TestConcurrent(t *testing.T) {
|
||||
|
||||
func spawnPeer(require *require.Assertions, logger *zap.Logger, netDialer *testdialer.BufconnDialer, netw *network, endpoint string) (*grpc.Server, *pubapi.API, *fakeVPN) {
|
||||
vpn := newVPN(netw, endpoint)
|
||||
cor, err := core.NewCore(vpn, &core.ClusterFake{}, &core.ProviderMetadataFake{}, &core.CloudControllerManagerFake{}, &core.CloudNodeManagerFake{}, &core.ClusterAutoscalerFake{}, &core.EncryptedDiskFake{}, logger, simulator.OpenSimulatedTPM, fakeStoreFactory{}, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
cor, err := core.NewCore(vpn, &core.ClusterFake{}, &core.ProviderMetadataFake{}, &core.CloudControllerManagerFake{}, &core.CloudNodeManagerFake{}, &core.ClusterAutoscalerFake{}, &core.EncryptedDiskFake{}, logger, simulator.OpenSimulatedTPM, fakeStoreFactory{}, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
require.NoError(cor.AdvanceState(state.AcceptingInit, nil, nil))
|
||||
|
||||
|
@ -6,11 +6,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/coordinator/kubernetes"
|
||||
"github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -171,7 +172,8 @@ func TestInitCluster(t *testing.T) {
|
||||
|
||||
zapLogger, err := zap.NewDevelopment()
|
||||
require.NoError(err)
|
||||
core, err := NewCore(&stubVPN{}, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, nil, zapLogger, simulator.OpenSimulatedTPM, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, nil, zapLogger, simulator.OpenSimulatedTPM, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
kubeconfig, err := core.InitCluster(tc.autoscalingNodeGroups, "cloud-service-account-uri")
|
||||
@ -286,7 +288,8 @@ func TestJoinCluster(t *testing.T) {
|
||||
|
||||
zapLogger, err := zap.NewDevelopment()
|
||||
require.NoError(err)
|
||||
core, err := NewCore(&tc.vpn, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, nil, zapLogger, simulator.OpenSimulatedTPM, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&tc.vpn, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, nil, zapLogger, simulator.OpenSimulatedTPM, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
joinReq := &kubeadm.BootstrapTokenDiscovery{
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/config"
|
||||
"github.com/edgelesssys/constellation/coordinator/nodestate"
|
||||
@ -18,6 +17,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/store"
|
||||
"github.com/edgelesssys/constellation/coordinator/storewrapper"
|
||||
"github.com/edgelesssys/constellation/coordinator/util"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/kms/kms"
|
||||
kmsSetup "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
"go.uber.org/zap"
|
||||
@ -44,12 +45,13 @@ type Core struct {
|
||||
initialVPNPeersRetriever initialVPNPeersRetriever
|
||||
lastHeartbeats map[string]time.Time
|
||||
fileHandler file.Handler
|
||||
linuxUserManager user.LinuxUserManager
|
||||
}
|
||||
|
||||
// NewCore creates and initializes a new Core object.
|
||||
func NewCore(vpn VPN, kube Cluster,
|
||||
metadata ProviderMetadata, cloudControllerManager CloudControllerManager, cloudNodeManager CloudNodeManager, clusterAutoscaler ClusterAutoscaler,
|
||||
encryptedDisk EncryptedDisk, zapLogger *zap.Logger, openTPM vtpm.TPMOpenFunc, persistentStoreFactory PersistentStoreFactory, fileHandler file.Handler,
|
||||
encryptedDisk EncryptedDisk, zapLogger *zap.Logger, openTPM vtpm.TPMOpenFunc, persistentStoreFactory PersistentStoreFactory, fileHandler file.Handler, linuxUserManager user.LinuxUserManager,
|
||||
) (*Core, error) {
|
||||
stor := store.NewStdStore()
|
||||
c := &Core{
|
||||
@ -68,6 +70,7 @@ func NewCore(vpn VPN, kube Cluster,
|
||||
initialVPNPeersRetriever: getInitialVPNPeers,
|
||||
lastHeartbeats: make(map[string]time.Time),
|
||||
fileHandler: fileHandler,
|
||||
linuxUserManager: linuxUserManager,
|
||||
}
|
||||
if err := c.data().IncrementPeersResourceVersion(); err != nil {
|
||||
return nil, err
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/nodestate"
|
||||
@ -16,6 +15,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/store"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/grpcutil"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/testdialer"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -36,7 +37,8 @@ func TestGetNextNodeIP(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
require.NoError(core.InitializeStoreIPs())
|
||||
|
||||
@ -79,7 +81,8 @@ func TestSwitchToPersistentStore(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
storeFactory := &fakeStoreFactory{}
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, storeFactory, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, storeFactory, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(core.store.Put("test", []byte("test")))
|
||||
require.NoError(err)
|
||||
|
||||
@ -93,7 +96,8 @@ func TestGetIDs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
_, _, err = core.GetIDs(nil)
|
||||
@ -117,7 +121,8 @@ func TestNotifyNodeHeartbeat(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
const ip = "192.0.2.1"
|
||||
@ -130,7 +135,8 @@ func TestDeriveKey(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
// error when no kms is set up
|
||||
@ -200,14 +206,15 @@ func TestInitialize(t *testing.T) {
|
||||
if tc.initializePCRs {
|
||||
require.NoError(vtpm.MarkNodeAsInitialized(openTPM, []byte{0x0, 0x1, 0x2, 0x3}, []byte{0x4, 0x5, 0x6, 0x7}))
|
||||
}
|
||||
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||
fs := afero.NewMemMapFs()
|
||||
fileHandler := file.NewHandler(fs)
|
||||
if tc.writeNodeState {
|
||||
require.NoError((&nodestate.NodeState{
|
||||
Role: tc.role,
|
||||
VPNPrivKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7},
|
||||
}).ToFile(fileHandler))
|
||||
}
|
||||
core, err := NewCore(&stubVPN{}, nil, &ProviderMetadataFake{}, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, &fakeStoreFactory{}, fileHandler)
|
||||
core, err := NewCore(&stubVPN{}, nil, &ProviderMetadataFake{}, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, &fakeStoreFactory{}, fileHandler, user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
core.initialVPNPeersRetriever = fakeInitializeVPNPeersRetriever
|
||||
// prepare store to emulate initialized KMS
|
||||
@ -265,7 +272,7 @@ func TestPersistNodeState(t *testing.T) {
|
||||
require.NoError(err)
|
||||
require.NoError(file.Close())
|
||||
}
|
||||
core, err := NewCore(tc.vpn, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, fileHandler)
|
||||
core, err := NewCore(tc.vpn, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, fileHandler, user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
err = core.PersistNodeState(role.Coordinator, "192.0.2.1", []byte("owner-id"), []byte("cluster-id"))
|
||||
if tc.wantErr {
|
||||
|
@ -4,7 +4,8 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -43,7 +44,8 @@ func TestGetDiskUUID(t *testing.T) {
|
||||
uuidErr: tc.uuidErr,
|
||||
uuid: tc.wantUUID,
|
||||
}
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, &diskStub, zapLogger, nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, &diskStub, zapLogger, nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
uuid, err := core.GetDiskUUID()
|
||||
if tc.wantErr {
|
||||
@ -85,7 +87,8 @@ func TestUpdateDiskPassphrase(t *testing.T) {
|
||||
openErr: tc.openErr,
|
||||
updatePassphraseErr: tc.updatePassphraseErr,
|
||||
}
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, &diskStub, zapLogger, nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, &diskStub, zapLogger, nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
err = core.UpdateDiskPassphrase("passphrase")
|
||||
if tc.wantErr {
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi"
|
||||
@ -18,6 +17,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/util/grpcutil"
|
||||
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
||||
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -131,7 +132,8 @@ func newMockCoreWithDialer(bufDialer *bufconnDialer) (*Core, *pubapi.API, error)
|
||||
getPublicAddr := func() (string, error) {
|
||||
return "192.0.2.1", nil
|
||||
}
|
||||
core, err := NewCore(vpn, kubeFake, metadataFake, ccmFake, cnmFake, autoscalerFake, encryptedDiskFake, zapLogger, simulator.OpenSimulatedTPM, &fakeStoreFactory{}, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(vpn, kubeFake, metadataFake, ccmFake, cnmFake, autoscalerFake, encryptedDiskFake, zapLogger, simulator.OpenSimulatedTPM, &fakeStoreFactory{}, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/peer"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -53,7 +54,8 @@ func TestGetPeers(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
// prepare store
|
||||
@ -113,7 +115,8 @@ func TestAddPeer(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
core, err := NewCore(&tc.vpn, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&tc.vpn, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
|
||||
err = core.AddPeer(tc.peer)
|
||||
|
@ -5,13 +5,14 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/peer"
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/grpcutil"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/testdialer"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -79,7 +80,8 @@ func TestReinitializeAsNode(t *testing.T) {
|
||||
go server.Serve(netDialer.GetListener("192.0.2.1:9000"))
|
||||
defer server.Stop()
|
||||
vpn := &stubVPN{}
|
||||
core, err := NewCore(vpn, nil, &stubMetadata{listRes: coordinators, supportedRes: true}, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(vpn, nil, &stubMetadata{listRes: coordinators, supportedRes: true}, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
err = core.ReinitializeAsNode(context.Background(), dialer, vpnIP, &stubPubAPI{}, 0)
|
||||
|
||||
@ -151,7 +153,8 @@ func TestReinitializeAsCoordinator(t *testing.T) {
|
||||
go server.Serve(netDialer.GetListener("192.0.2.1:9000"))
|
||||
defer server.Stop()
|
||||
vpn := &stubVPN{}
|
||||
core, err := NewCore(vpn, nil, &stubMetadata{listRes: coordinators, supportedRes: true}, nil, nil, nil, nil, zaptest.NewLogger(t), nil, &fakeStoreFactory{}, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(vpn, nil, &stubMetadata{listRes: coordinators, supportedRes: true}, nil, nil, nil, nil, zaptest.NewLogger(t), nil, &fakeStoreFactory{}, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
// prepare store to emulate initialized KMS
|
||||
require.NoError(core.data().PutKMSData(kms.KMSInformation{StorageUri: kms.NoStoreURI, KmsUri: kms.ClusterKMSURI}))
|
||||
|
21
coordinator/core/ssh.go
Normal file
21
coordinator/core/ssh.go
Normal file
@ -0,0 +1,21 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
)
|
||||
|
||||
// CreateSSHUsers creates UNIX users with respective SSH access on the system the coordinator is running on when defined in the config.
|
||||
func (c *Core) CreateSSHUsers(sshUserKeys []ssh.UserKey) error {
|
||||
sshAccess := ssh.NewSSHAccess(c.linuxUserManager)
|
||||
ctx := context.Background()
|
||||
|
||||
for _, pair := range sshUserKeys {
|
||||
if err := sshAccess.DeploySSHAuthorizedKey(ctx, pair); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -5,9 +5,10 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -65,7 +66,8 @@ func TestAdvanceState(t *testing.T) {
|
||||
return simulator.OpenSimulatedTPM()
|
||||
}
|
||||
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||
fs := afero.NewMemMapFs()
|
||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||
require.NoError(err)
|
||||
assert.Equal(state.Uninitialized, core.GetState())
|
||||
core.state = tc.initialState
|
||||
|
@ -3,8 +3,8 @@ package nodestate
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
)
|
||||
|
||||
const nodeStatePath = "/run/state/constellation/node_state.json"
|
||||
|
@ -4,8 +4,8 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/state/keyservice/keyproto"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc/codes"
|
||||
@ -88,6 +89,15 @@ func (a *API) ActivateAsCoordinator(in *pubproto.ActivateAsCoordinatorRequest, s
|
||||
return status.Errorf(codes.Internal, "adding the coordinator to store/vpn: %v", err)
|
||||
}
|
||||
|
||||
// Setup SSH users for the first coordinator, if defined
|
||||
if len(in.SshUserKeys) != 0 {
|
||||
logToCLI("Creating SSH users on first control-plane node...")
|
||||
sshUserKeys := ssh.FromProtoSlice(in.SshUserKeys)
|
||||
if err := a.core.CreateSSHUsers(sshUserKeys); err != nil {
|
||||
return status.Errorf(codes.Internal, "creating SSH users: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
logToCLI("Initializing Kubernetes ...")
|
||||
kubeconfig, err := a.core.InitCluster(in.AutoscalingNodeGroups, in.CloudServiceAccountUri)
|
||||
if err != nil {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
@ -19,8 +20,11 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/grpcutil"
|
||||
"github.com/edgelesssys/constellation/coordinator/util/testdialer"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
"github.com/edgelesssys/constellation/state/keyservice/keyproto"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
@ -40,6 +44,14 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
wantNode3 := peer.Peer{PublicIP: "192.0.2.13", VPNIP: "10.118.0.13", VPNPubKey: []byte{3, 4, 5}, Role: role.Node}
|
||||
wantCoord := peer.Peer{PublicIP: "192.0.2.1", VPNIP: "10.118.0.1", VPNPubKey: coordinatorPubKey, Role: role.Coordinator}
|
||||
adminPeer := peer.Peer{VPNPubKey: []byte{7, 8, 9}, Role: role.Admin}
|
||||
sshUser1 := &ssh.UserKey{
|
||||
Username: "test-user-1",
|
||||
PublicKey: "ssh-rsa abcdefg",
|
||||
}
|
||||
sshUser2 := &ssh.UserKey{
|
||||
Username: "test-user-2",
|
||||
PublicKey: "ssh-ed25519 hijklmn",
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
nodes []*stubPeer
|
||||
@ -49,6 +61,7 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
wantPeers []peer.Peer
|
||||
wantState state.State
|
||||
adminVPNIP string
|
||||
sshKeys []*ssh.UserKey
|
||||
}{
|
||||
"0 nodes": {
|
||||
state: state.AcceptingInit,
|
||||
@ -77,6 +90,13 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
wantState: state.ActivatingNodes,
|
||||
adminVPNIP: "10.118.0.14",
|
||||
},
|
||||
"coordinator with SSH users": {
|
||||
state: state.AcceptingInit,
|
||||
wantPeers: []peer.Peer{wantCoord},
|
||||
wantState: state.ActivatingNodes,
|
||||
adminVPNIP: "10.118.0.11",
|
||||
sshKeys: []*ssh.UserKey{sshUser1, sshUser2},
|
||||
},
|
||||
"already activated": {
|
||||
nodes: []*stubPeer{testNode1},
|
||||
state: state.ActivatingNodes,
|
||||
@ -117,7 +137,7 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
|
||||
autoscalingNodeGroups := []string{"ang1", "ang2"}
|
||||
keyEncryptionKeyID := "constellation"
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
core := &fakeCore{
|
||||
state: tc.state,
|
||||
vpnPubKey: coordinatorPubKey,
|
||||
@ -125,7 +145,9 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
kubeconfig: []byte("kubeconfig"),
|
||||
ownerID: []byte("ownerID"),
|
||||
clusterID: []byte("clusterID"),
|
||||
linuxUserManager: user.NewLinuxUserManagerFake(fs),
|
||||
}
|
||||
|
||||
netDialer := testdialer.NewBufconnDialer()
|
||||
dialer := grpcutil.NewDialer(fakeValidator{}, netDialer)
|
||||
|
||||
@ -162,6 +184,7 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
UseExistingKek: false,
|
||||
KmsUri: kms.ClusterKMSURI,
|
||||
StorageUri: kms.NoStoreURI,
|
||||
SshUserKeys: ssh.ToProtoSlice(tc.sshKeys),
|
||||
}, stream)
|
||||
|
||||
assert.Equal(tc.wantState, core.state)
|
||||
@ -194,6 +217,25 @@ func TestActivateAsCoordinator(t *testing.T) {
|
||||
assert.Equal(autoscalingNodeGroups, core.autoscalingNodeGroups)
|
||||
assert.Equal(keyEncryptionKeyID, core.kekID)
|
||||
assert.Equal([]role.Role{role.Coordinator}, core.persistNodeStateRoles)
|
||||
|
||||
// Test SSH user & key creation. Both cases: "supposed to add" and "not supposed to add"
|
||||
// This slightly differs from a real environment (e.g. missing /home) but should be fine in the stub context with a virtual file system
|
||||
if tc.sshKeys != nil {
|
||||
passwd := user.Passwd{}
|
||||
entries, err := passwd.Parse(fs)
|
||||
require.NoError(err)
|
||||
for _, singleEntry := range entries {
|
||||
username := singleEntry.Gecos
|
||||
_, err := fs.Stat(fmt.Sprintf("/home/%s/.ssh/authorized_keys.d/ssh-keys", username))
|
||||
assert.NoError(err)
|
||||
}
|
||||
} else {
|
||||
passwd := user.Passwd{}
|
||||
_, err := passwd.Parse(fs)
|
||||
assert.EqualError(err, "open /etc/passwd: file does not exist")
|
||||
_, err = fs.Stat("/home")
|
||||
assert.EqualError(err, "open /home: file does not exist")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/peer"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
|
||||
)
|
||||
@ -36,6 +37,8 @@ type Core interface {
|
||||
AddPeerToVPN(peer.Peer) error
|
||||
UpdatePeers([]peer.Peer) error
|
||||
|
||||
CreateSSHUsers([]ssh.UserKey) error
|
||||
|
||||
InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string) ([]byte, error)
|
||||
JoinCluster(joinToken *kubeadm.BootstrapTokenDiscovery, certificateKey string, role role.Role) error
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/peer"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
kms "github.com/edgelesssys/constellation/kms/server/setup"
|
||||
kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
|
||||
)
|
||||
@ -36,6 +38,7 @@ type fakeCore struct {
|
||||
kekID string
|
||||
dataKey []byte
|
||||
getDataKeyErr error
|
||||
linuxUserManager user.LinuxUserManager
|
||||
}
|
||||
|
||||
func (c *fakeCore) GetVPNPubKey() ([]byte, error) {
|
||||
@ -154,3 +157,16 @@ func (c *fakeCore) GetDiskUUID() (string, error) {
|
||||
func (c *fakeCore) UpdateDiskPassphrase(passphrase string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeCore) CreateSSHUsers(sshUserKeys []ssh.UserKey) error {
|
||||
sshAccess := ssh.NewSSHAccess(c.linuxUserManager)
|
||||
ctx := context.Background()
|
||||
|
||||
for _, pair := range sshUserKeys {
|
||||
if err := sshAccess.DeploySSHAuthorizedKey(ctx, pair); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -110,16 +110,17 @@ type ActivateAsCoordinatorRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AdminVpnPubKey []byte `protobuf:"bytes,1,opt,name=admin_vpn_pub_key,json=adminVpnPubKey,proto3" json:"admin_vpn_pub_key,omitempty"`
|
||||
NodePublicIps []string `protobuf:"bytes,2,rep,name=node_public_ips,json=nodePublicIps,proto3" json:"node_public_ips,omitempty"`
|
||||
CoordinatorPublicIps []string `protobuf:"bytes,3,rep,name=coordinator_public_ips,json=coordinatorPublicIps,proto3" json:"coordinator_public_ips,omitempty"`
|
||||
AutoscalingNodeGroups []string `protobuf:"bytes,4,rep,name=autoscaling_node_groups,json=autoscalingNodeGroups,proto3" json:"autoscaling_node_groups,omitempty"`
|
||||
MasterSecret []byte `protobuf:"bytes,5,opt,name=master_secret,json=masterSecret,proto3" json:"master_secret,omitempty"`
|
||||
KmsUri string `protobuf:"bytes,6,opt,name=kms_uri,json=kmsUri,proto3" json:"kms_uri,omitempty"`
|
||||
StorageUri string `protobuf:"bytes,7,opt,name=storage_uri,json=storageUri,proto3" json:"storage_uri,omitempty"`
|
||||
KeyEncryptionKeyId string `protobuf:"bytes,8,opt,name=key_encryption_key_id,json=keyEncryptionKeyId,proto3" json:"key_encryption_key_id,omitempty"`
|
||||
UseExistingKek bool `protobuf:"varint,9,opt,name=use_existing_kek,json=useExistingKek,proto3" json:"use_existing_kek,omitempty"`
|
||||
CloudServiceAccountUri string `protobuf:"bytes,10,opt,name=cloud_service_account_uri,json=cloudServiceAccountUri,proto3" json:"cloud_service_account_uri,omitempty"`
|
||||
AdminVpnPubKey []byte `protobuf:"bytes,1,opt,name=admin_vpn_pub_key,json=adminVpnPubKey,proto3" json:"admin_vpn_pub_key,omitempty"`
|
||||
NodePublicIps []string `protobuf:"bytes,2,rep,name=node_public_ips,json=nodePublicIps,proto3" json:"node_public_ips,omitempty"`
|
||||
CoordinatorPublicIps []string `protobuf:"bytes,3,rep,name=coordinator_public_ips,json=coordinatorPublicIps,proto3" json:"coordinator_public_ips,omitempty"`
|
||||
AutoscalingNodeGroups []string `protobuf:"bytes,4,rep,name=autoscaling_node_groups,json=autoscalingNodeGroups,proto3" json:"autoscaling_node_groups,omitempty"`
|
||||
MasterSecret []byte `protobuf:"bytes,5,opt,name=master_secret,json=masterSecret,proto3" json:"master_secret,omitempty"`
|
||||
KmsUri string `protobuf:"bytes,6,opt,name=kms_uri,json=kmsUri,proto3" json:"kms_uri,omitempty"`
|
||||
StorageUri string `protobuf:"bytes,7,opt,name=storage_uri,json=storageUri,proto3" json:"storage_uri,omitempty"`
|
||||
KeyEncryptionKeyId string `protobuf:"bytes,8,opt,name=key_encryption_key_id,json=keyEncryptionKeyId,proto3" json:"key_encryption_key_id,omitempty"`
|
||||
UseExistingKek bool `protobuf:"varint,9,opt,name=use_existing_kek,json=useExistingKek,proto3" json:"use_existing_kek,omitempty"`
|
||||
CloudServiceAccountUri string `protobuf:"bytes,10,opt,name=cloud_service_account_uri,json=cloudServiceAccountUri,proto3" json:"cloud_service_account_uri,omitempty"`
|
||||
SshUserKeys []*SSHUserKey `protobuf:"bytes,11,rep,name=ssh_user_keys,json=sshUserKeys,proto3" json:"ssh_user_keys,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ActivateAsCoordinatorRequest) Reset() {
|
||||
@ -224,6 +225,13 @@ func (x *ActivateAsCoordinatorRequest) GetCloudServiceAccountUri() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActivateAsCoordinatorRequest) GetSshUserKeys() []*SSHUserKey {
|
||||
if x != nil {
|
||||
return x.SshUserKeys
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ActivateAsCoordinatorResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -1520,6 +1528,61 @@ func (x *Peer) GetRole() uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type SSHUserKey struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SSHUserKey) Reset() {
|
||||
*x = SSHUserKey{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pubapi_proto_msgTypes[28]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SSHUserKey) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SSHUserKey) ProtoMessage() {}
|
||||
|
||||
func (x *SSHUserKey) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pubapi_proto_msgTypes[28]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SSHUserKey.ProtoReflect.Descriptor instead.
|
||||
func (*SSHUserKey) Descriptor() ([]byte, []int) {
|
||||
return file_pubapi_proto_rawDescGZIP(), []int{28}
|
||||
}
|
||||
|
||||
func (x *SSHUserKey) GetUsername() string {
|
||||
if x != nil {
|
||||
return x.Username
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SSHUserKey) GetPublicKey() string {
|
||||
if x != nil {
|
||||
return x.PublicKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_pubapi_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_pubapi_proto_rawDesc = []byte{
|
||||
@ -1528,7 +1591,7 @@ var file_pubapi_proto_rawDesc = []byte{
|
||||
0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x28, 0x0a, 0x10, 0x47, 0x65, 0x74,
|
||||
0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74,
|
||||
0x61, 0x74, 0x65, 0x22, 0xd6, 0x03, 0x0a, 0x1c, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x61, 0x74, 0x65, 0x22, 0x8e, 0x04, 0x0a, 0x1c, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x11, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x70,
|
||||
0x6e, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
@ -1557,209 +1620,217 @@ var file_pubapi_proto_rawDesc = []byte{
|
||||
0x6b, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x72, 0x69, 0x22, 0x85, 0x01, 0x0a,
|
||||
0x1d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64,
|
||||
0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38,
|
||||
0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64,
|
||||
0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x0b, 0x61, 0x64, 0x6d,
|
||||
0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4c,
|
||||
0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x65, 0x6e, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x15, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f,
|
||||
0x0a, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x49,
|
||||
0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52,
|
||||
0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x26, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||
0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x22, 0x9c, 0x01, 0x0a, 0x1c, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41,
|
||||
0x73, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x76, 0x70, 0x6e, 0x5f,
|
||||
0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x56, 0x70,
|
||||
0x6e, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x65, 0x65, 0x72,
|
||||
0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49,
|
||||
0x64, 0x22, 0x79, 0x0a, 0x16, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e,
|
||||
0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6e,
|
||||
0x6f, 0x64, 0x65, 0x5f, 0x76, 0x70, 0x6e, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x56, 0x70, 0x6e,
|
||||
0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f,
|
||||
0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||
0x00, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x75, 0x69, 0x64,
|
||||
0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, 0x1e,
|
||||
0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26,
|
||||
0x0a, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x70,
|
||||
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62,
|
||||
0x6c, 0x69, 0x63, 0x49, 0x70, 0x73, 0x22, 0x40, 0x0a, 0x1f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x03, 0x6c, 0x6f, 0x67,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x4c, 0x6f, 0x67, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x22, 0xfc, 0x01, 0x0a, 0x26, 0x41, 0x63, 0x74,
|
||||
0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61,
|
||||
0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f,
|
||||
0x76, 0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x73,
|
||||
0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x70, 0x6e, 0x49, 0x70, 0x12, 0x4c, 0x0a, 0x1b, 0x61,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x19,
|
||||
0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x05, 0x70, 0x65, 0x65,
|
||||
0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a,
|
||||
0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c,
|
||||
0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x29, 0x0a, 0x27, 0x41, 0x63, 0x74, 0x69, 0x76,
|
||||
0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43,
|
||||
0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x5a, 0x0a, 0x24, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64,
|
||||
0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
|
||||
0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f,
|
||||
0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6f, 0x72, 0x64,
|
||||
0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x70, 0x22, 0x27,
|
||||
0x0a, 0x25, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x0a, 0x12, 0x4a, 0x6f, 0x69, 0x6e, 0x43,
|
||||
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a,
|
||||
0x12, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x76, 0x70, 0x6e,
|
||||
0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6f, 0x72, 0x64,
|
||||
0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x70, 0x6e, 0x49, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x4a,
|
||||
0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64,
|
||||
0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x1b,
|
||||
0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x54,
|
||||
0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x22,
|
||||
0x0a, 0x20, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x39, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61,
|
||||
0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55, 0x75, 0x69, 0x64, 0x22, 0x1d, 0x0a,
|
||||
0x1b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73,
|
||||
0x6b, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x0a, 0x1a,
|
||||
0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x56, 0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x1b, 0x47, 0x65,
|
||||
0x74, 0x50, 0x65, 0x65, 0x72, 0x56, 0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
|
||||
0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, 0x6f,
|
||||
0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
|
||||
0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74,
|
||||
0x56, 0x50, 0x4e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
|
||||
0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x56, 0x50, 0x4e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18,
|
||||
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x50,
|
||||
0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x0b, 0x41,
|
||||
0x64, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x64,
|
||||
0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x56, 0x70, 0x6e, 0x49, 0x70, 0x12, 0x35, 0x0a, 0x17,
|
||||
0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x76, 0x70, 0x6e, 0x5f,
|
||||
0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x63,
|
||||
0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x70, 0x6e, 0x50, 0x75, 0x62,
|
||||
0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x1f, 0x0a,
|
||||
0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x6e,
|
||||
0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x63, 0x49, 0x70, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x6e, 0x49, 0x70, 0x12, 0x1e, 0x0a, 0x0b, 0x76, 0x70,
|
||||
0x6e, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x09, 0x76, 0x70, 0x6e, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f,
|
||||
0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x32, 0x8b,
|
||||
0x09, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x3d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61,
|
||||
0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x75,
|
||||
0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x15, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x24,
|
||||
0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63,
|
||||
0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
|
||||
0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x53, 0x0a,
|
||||
0x0e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12,
|
||||
0x1d, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
|
||||
0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01,
|
||||
0x30, 0x01, 0x12, 0x6c, 0x0a, 0x17, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64,
|
||||
0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x26, 0x2e,
|
||||
0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41,
|
||||
0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61,
|
||||
0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01,
|
||||
0x12, 0x82, 0x01, 0x0a, 0x1f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41,
|
||||
0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x72, 0x69, 0x12, 0x36, 0x0a, 0x0d,
|
||||
0x73, 0x73, 0x68, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x0b, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x53, 0x48,
|
||||
0x55, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x73, 0x73, 0x68, 0x55, 0x73, 0x65, 0x72,
|
||||
0x4b, 0x65, 0x79, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x1d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f,
|
||||
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
|
||||
0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x48, 0x00, 0x52, 0x0b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x1f, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e,
|
||||
0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f,
|
||||
0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x9b, 0x01, 0x0a,
|
||||
0x15, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x24, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||
0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48,
|
||||
0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x42,
|
||||
0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9c, 0x01, 0x0a, 0x1c, 0x41,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x69,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x6e,
|
||||
0x6f, 0x64, 0x65, 0x5f, 0x76, 0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x56, 0x70, 0x6e, 0x49, 0x70, 0x12, 0x22, 0x0a, 0x05, 0x70,
|
||||
0x65, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12,
|
||||
0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c,
|
||||
0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
|
||||
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x79, 0x0a, 0x16, 0x41, 0x63, 0x74,
|
||||
0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x76, 0x70, 0x6e, 0x5f,
|
||||
0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52,
|
||||
0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x56, 0x70, 0x6e, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x28,
|
||||
0x0a, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75, 0x75, 0x69,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||
0x44, 0x69, 0x73, 0x6b, 0x55, 0x75, 0x69, 0x64, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, 0x1e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70,
|
||||
0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x70, 0x73, 0x22, 0x40,
|
||||
0x0a, 0x1f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x1d, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b,
|
||||
0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x03, 0x6c, 0x6f, 0x67,
|
||||
0x22, 0xfc, 0x01, 0x0a, 0x26, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41,
|
||||
0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x12, 0x2e, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63,
|
||||
0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63,
|
||||
0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x1d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64,
|
||||
0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x61,
|
||||
0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x76, 0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x56, 0x70,
|
||||
0x6e, 0x49, 0x70, 0x12, 0x4c, 0x0a, 0x1b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x64, 0x61,
|
||||
0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x19, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x61, 0x74,
|
||||
0x61, 0x12, 0x22, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05,
|
||||
0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22,
|
||||
0x29, 0x0a, 0x27, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64,
|
||||
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x0a, 0x24, 0x41, 0x63,
|
||||
0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
|
||||
0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x4a, 0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74,
|
||||
0x65, 0x72, 0x12, 0x1a, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69, 0x6e,
|
||||
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b,
|
||||
0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x11, 0x54,
|
||||
0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||
0x12, 0x20, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67,
|
||||
0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x18, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72,
|
||||
0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74,
|
||||
0x65, 0x12, 0x27, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67,
|
||||
0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x75, 0x62,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64,
|
||||
0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x56,
|
||||
0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x2e, 0x70, 0x75,
|
||||
0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x56, 0x50, 0x4e, 0x50,
|
||||
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x23, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72,
|
||||
0x56, 0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x56, 0x50, 0x4e, 0x50, 0x65,
|
||||
0x65, 0x72, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x56, 0x50, 0x4e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1b, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x50, 0x4e, 0x50,
|
||||
0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x13,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b,
|
||||
0x4b, 0x65, 0x79, 0x12, 0x22, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73,
|
||||
0x6b, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x42, 0x5a, 0x40,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x6c,
|
||||
0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72,
|
||||
0x2f, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x75, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x13, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75,
|
||||
0x62, 0x6c, 0x69, 0x63, 0x49, 0x70, 0x22, 0x27, 0x0a, 0x25, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72,
|
||||
0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x42, 0x0a, 0x12, 0x4a, 0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x5f, 0x76, 0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x10, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x70,
|
||||
0x6e, 0x49, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x4a, 0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74,
|
||||
0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x54, 0x72,
|
||||
0x69, 0x67, 0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x6f,
|
||||
0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x22, 0x0a, 0x20, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x0a, 0x1a, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65,
|
||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b,
|
||||
0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x69, 0x73,
|
||||
0x6b, 0x55, 0x75, 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x56,
|
||||
0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x22, 0x4d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x56, 0x50, 0x4e,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72,
|
||||
0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11,
|
||||
0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65,
|
||||
0x79, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x56, 0x50, 0x4e, 0x50, 0x65, 0x65, 0x72, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x56, 0x50,
|
||||
0x4e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22,
|
||||
0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
|
||||
0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65,
|
||||
0x72, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x0b, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x70, 0x6e, 0x5f,
|
||||
0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x56,
|
||||
0x70, 0x6e, 0x49, 0x70, 0x12, 0x35, 0x0a, 0x17, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
|
||||
0x74, 0x6f, 0x72, 0x5f, 0x76, 0x70, 0x6e, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x6f, 0x72, 0x56, 0x70, 0x6e, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x6b,
|
||||
0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x6f,
|
||||
0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f,
|
||||
0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||
0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x1f, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x6e, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x70, 0x12, 0x15, 0x0a, 0x06, 0x76,
|
||||
0x70, 0x6e, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x6e,
|
||||
0x49, 0x70, 0x12, 0x1e, 0x0a, 0x0b, 0x76, 0x70, 0x6e, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x76, 0x70, 0x6e, 0x50, 0x75, 0x62, 0x4b,
|
||||
0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0a, 0x53, 0x53, 0x48, 0x55, 0x73, 0x65,
|
||||
0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x32,
|
||||
0x8b, 0x09, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x3d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74,
|
||||
0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70,
|
||||
0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x15, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12,
|
||||
0x24, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x53,
|
||||
0x0a, 0x0e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65,
|
||||
0x12, 0x1d, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1e, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x41, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28,
|
||||
0x01, 0x30, 0x01, 0x12, 0x6c, 0x0a, 0x17, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41,
|
||||
0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x26,
|
||||
0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30,
|
||||
0x01, 0x12, 0x82, 0x01, 0x0a, 0x1f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73,
|
||||
0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2e, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x73, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x1d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72,
|
||||
0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2c, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61,
|
||||
0x6c, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x4a, 0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69,
|
||||
0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1b, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x43, 0x6c, 0x75,
|
||||
0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x11,
|
||||
0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74,
|
||||
0x65, 0x12, 0x20, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67,
|
||||
0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69,
|
||||
0x67, 0x67, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x18, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x12, 0x27, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67,
|
||||
0x67, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x75,
|
||||
0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72,
|
||||
0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72,
|
||||
0x56, 0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x2e, 0x70,
|
||||
0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x56, 0x50, 0x4e,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x23, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65,
|
||||
0x72, 0x56, 0x50, 0x4e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x56, 0x50, 0x4e, 0x50,
|
||||
0x65, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65,
|
||||
0x74, 0x56, 0x50, 0x4e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x1b, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x50, 0x4e,
|
||||
0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a,
|
||||
0x13, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73,
|
||||
0x6b, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65,
|
||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x75, 0x62, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x44, 0x69,
|
||||
0x73, 0x6b, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x42, 0x5a,
|
||||
0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65,
|
||||
0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x2f, 0x70, 0x75, 0x62, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x75, 0x62, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -1774,7 +1845,7 @@ func file_pubapi_proto_rawDescGZIP() []byte {
|
||||
return file_pubapi_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_pubapi_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
|
||||
var file_pubapi_proto_msgTypes = make([]protoimpl.MessageInfo, 29)
|
||||
var file_pubapi_proto_goTypes = []interface{}{
|
||||
(*GetStateRequest)(nil), // 0: pubapi.GetStateRequest
|
||||
(*GetStateResponse)(nil), // 1: pubapi.GetStateResponse
|
||||
@ -1804,45 +1875,47 @@ var file_pubapi_proto_goTypes = []interface{}{
|
||||
(*AdminConfig)(nil), // 25: pubapi.AdminConfig
|
||||
(*Log)(nil), // 26: pubapi.Log
|
||||
(*Peer)(nil), // 27: pubapi.Peer
|
||||
(*SSHUserKey)(nil), // 28: pubapi.SSHUserKey
|
||||
}
|
||||
var file_pubapi_proto_depIdxs = []int32{
|
||||
25, // 0: pubapi.ActivateAsCoordinatorResponse.admin_config:type_name -> pubapi.AdminConfig
|
||||
26, // 1: pubapi.ActivateAsCoordinatorResponse.log:type_name -> pubapi.Log
|
||||
5, // 2: pubapi.ActivateAsNodeRequest.initial_request:type_name -> pubapi.ActivateAsNodeInitialRequest
|
||||
27, // 3: pubapi.ActivateAsNodeInitialRequest.peers:type_name -> pubapi.Peer
|
||||
26, // 4: pubapi.ActivateAdditionalNodesResponse.log:type_name -> pubapi.Log
|
||||
27, // 5: pubapi.ActivateAsAdditionalCoordinatorRequest.activating_coordinator_data:type_name -> pubapi.Peer
|
||||
27, // 6: pubapi.ActivateAsAdditionalCoordinatorRequest.peers:type_name -> pubapi.Peer
|
||||
27, // 7: pubapi.GetVPNPeersResponse.peers:type_name -> pubapi.Peer
|
||||
0, // 8: pubapi.API.GetState:input_type -> pubapi.GetStateRequest
|
||||
2, // 9: pubapi.API.ActivateAsCoordinator:input_type -> pubapi.ActivateAsCoordinatorRequest
|
||||
4, // 10: pubapi.API.ActivateAsNode:input_type -> pubapi.ActivateAsNodeRequest
|
||||
7, // 11: pubapi.API.ActivateAdditionalNodes:input_type -> pubapi.ActivateAdditionalNodesRequest
|
||||
9, // 12: pubapi.API.ActivateAsAdditionalCoordinator:input_type -> pubapi.ActivateAsAdditionalCoordinatorRequest
|
||||
11, // 13: pubapi.API.ActivateAdditionalCoordinator:input_type -> pubapi.ActivateAdditionalCoordinatorRequest
|
||||
13, // 14: pubapi.API.JoinCluster:input_type -> pubapi.JoinClusterRequest
|
||||
15, // 15: pubapi.API.TriggerNodeUpdate:input_type -> pubapi.TriggerNodeUpdateRequest
|
||||
17, // 16: pubapi.API.TriggerCoordinatorUpdate:input_type -> pubapi.TriggerCoordinatorUpdateRequest
|
||||
21, // 17: pubapi.API.GetPeerVPNPublicKey:input_type -> pubapi.GetPeerVPNPublicKeyRequest
|
||||
23, // 18: pubapi.API.GetVPNPeers:input_type -> pubapi.GetVPNPeersRequest
|
||||
19, // 19: pubapi.API.RequestStateDiskKey:input_type -> pubapi.RequestStateDiskKeyRequest
|
||||
1, // 20: pubapi.API.GetState:output_type -> pubapi.GetStateResponse
|
||||
3, // 21: pubapi.API.ActivateAsCoordinator:output_type -> pubapi.ActivateAsCoordinatorResponse
|
||||
6, // 22: pubapi.API.ActivateAsNode:output_type -> pubapi.ActivateAsNodeResponse
|
||||
8, // 23: pubapi.API.ActivateAdditionalNodes:output_type -> pubapi.ActivateAdditionalNodesResponse
|
||||
10, // 24: pubapi.API.ActivateAsAdditionalCoordinator:output_type -> pubapi.ActivateAsAdditionalCoordinatorResponse
|
||||
12, // 25: pubapi.API.ActivateAdditionalCoordinator:output_type -> pubapi.ActivateAdditionalCoordinatorResponse
|
||||
14, // 26: pubapi.API.JoinCluster:output_type -> pubapi.JoinClusterResponse
|
||||
16, // 27: pubapi.API.TriggerNodeUpdate:output_type -> pubapi.TriggerNodeUpdateResponse
|
||||
18, // 28: pubapi.API.TriggerCoordinatorUpdate:output_type -> pubapi.TriggerCoordinatorUpdateResponse
|
||||
22, // 29: pubapi.API.GetPeerVPNPublicKey:output_type -> pubapi.GetPeerVPNPublicKeyResponse
|
||||
24, // 30: pubapi.API.GetVPNPeers:output_type -> pubapi.GetVPNPeersResponse
|
||||
20, // 31: pubapi.API.RequestStateDiskKey:output_type -> pubapi.RequestStateDiskKeyResponse
|
||||
20, // [20:32] is the sub-list for method output_type
|
||||
8, // [8:20] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
28, // 0: pubapi.ActivateAsCoordinatorRequest.ssh_user_keys:type_name -> pubapi.SSHUserKey
|
||||
25, // 1: pubapi.ActivateAsCoordinatorResponse.admin_config:type_name -> pubapi.AdminConfig
|
||||
26, // 2: pubapi.ActivateAsCoordinatorResponse.log:type_name -> pubapi.Log
|
||||
5, // 3: pubapi.ActivateAsNodeRequest.initial_request:type_name -> pubapi.ActivateAsNodeInitialRequest
|
||||
27, // 4: pubapi.ActivateAsNodeInitialRequest.peers:type_name -> pubapi.Peer
|
||||
26, // 5: pubapi.ActivateAdditionalNodesResponse.log:type_name -> pubapi.Log
|
||||
27, // 6: pubapi.ActivateAsAdditionalCoordinatorRequest.activating_coordinator_data:type_name -> pubapi.Peer
|
||||
27, // 7: pubapi.ActivateAsAdditionalCoordinatorRequest.peers:type_name -> pubapi.Peer
|
||||
27, // 8: pubapi.GetVPNPeersResponse.peers:type_name -> pubapi.Peer
|
||||
0, // 9: pubapi.API.GetState:input_type -> pubapi.GetStateRequest
|
||||
2, // 10: pubapi.API.ActivateAsCoordinator:input_type -> pubapi.ActivateAsCoordinatorRequest
|
||||
4, // 11: pubapi.API.ActivateAsNode:input_type -> pubapi.ActivateAsNodeRequest
|
||||
7, // 12: pubapi.API.ActivateAdditionalNodes:input_type -> pubapi.ActivateAdditionalNodesRequest
|
||||
9, // 13: pubapi.API.ActivateAsAdditionalCoordinator:input_type -> pubapi.ActivateAsAdditionalCoordinatorRequest
|
||||
11, // 14: pubapi.API.ActivateAdditionalCoordinator:input_type -> pubapi.ActivateAdditionalCoordinatorRequest
|
||||
13, // 15: pubapi.API.JoinCluster:input_type -> pubapi.JoinClusterRequest
|
||||
15, // 16: pubapi.API.TriggerNodeUpdate:input_type -> pubapi.TriggerNodeUpdateRequest
|
||||
17, // 17: pubapi.API.TriggerCoordinatorUpdate:input_type -> pubapi.TriggerCoordinatorUpdateRequest
|
||||
21, // 18: pubapi.API.GetPeerVPNPublicKey:input_type -> pubapi.GetPeerVPNPublicKeyRequest
|
||||
23, // 19: pubapi.API.GetVPNPeers:input_type -> pubapi.GetVPNPeersRequest
|
||||
19, // 20: pubapi.API.RequestStateDiskKey:input_type -> pubapi.RequestStateDiskKeyRequest
|
||||
1, // 21: pubapi.API.GetState:output_type -> pubapi.GetStateResponse
|
||||
3, // 22: pubapi.API.ActivateAsCoordinator:output_type -> pubapi.ActivateAsCoordinatorResponse
|
||||
6, // 23: pubapi.API.ActivateAsNode:output_type -> pubapi.ActivateAsNodeResponse
|
||||
8, // 24: pubapi.API.ActivateAdditionalNodes:output_type -> pubapi.ActivateAdditionalNodesResponse
|
||||
10, // 25: pubapi.API.ActivateAsAdditionalCoordinator:output_type -> pubapi.ActivateAsAdditionalCoordinatorResponse
|
||||
12, // 26: pubapi.API.ActivateAdditionalCoordinator:output_type -> pubapi.ActivateAdditionalCoordinatorResponse
|
||||
14, // 27: pubapi.API.JoinCluster:output_type -> pubapi.JoinClusterResponse
|
||||
16, // 28: pubapi.API.TriggerNodeUpdate:output_type -> pubapi.TriggerNodeUpdateResponse
|
||||
18, // 29: pubapi.API.TriggerCoordinatorUpdate:output_type -> pubapi.TriggerCoordinatorUpdateResponse
|
||||
22, // 30: pubapi.API.GetPeerVPNPublicKey:output_type -> pubapi.GetPeerVPNPublicKeyResponse
|
||||
24, // 31: pubapi.API.GetVPNPeers:output_type -> pubapi.GetVPNPeersResponse
|
||||
20, // 32: pubapi.API.RequestStateDiskKey:output_type -> pubapi.RequestStateDiskKeyResponse
|
||||
21, // [21:33] is the sub-list for method output_type
|
||||
9, // [9:21] is the sub-list for method input_type
|
||||
9, // [9:9] is the sub-list for extension type_name
|
||||
9, // [9:9] is the sub-list for extension extendee
|
||||
0, // [0:9] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pubapi_proto_init() }
|
||||
@ -2187,6 +2260,18 @@ func file_pubapi_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_pubapi_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SSHUserKey); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_pubapi_proto_msgTypes[3].OneofWrappers = []interface{}{
|
||||
(*ActivateAsCoordinatorResponse_AdminConfig)(nil),
|
||||
@ -2206,7 +2291,7 @@ func file_pubapi_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_pubapi_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 28,
|
||||
NumMessages: 29,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
@ -37,6 +37,7 @@ message ActivateAsCoordinatorRequest {
|
||||
string key_encryption_key_id = 8;
|
||||
bool use_existing_kek = 9;
|
||||
string cloud_service_account_uri = 10;
|
||||
repeated SSHUserKey ssh_user_keys = 11;
|
||||
}
|
||||
|
||||
message ActivateAsCoordinatorResponse {
|
||||
@ -152,3 +153,8 @@ message Peer {
|
||||
bytes vpn_pub_key = 3;
|
||||
uint32 role = 4;
|
||||
}
|
||||
|
||||
message SSHUserKey {
|
||||
string username = 1;
|
||||
string public_key = 2;
|
||||
}
|
||||
|
@ -8,16 +8,16 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/debugd/cdbg/config"
|
||||
"github.com/edgelesssys/constellation/debugd/cdbg/state"
|
||||
"github.com/edgelesssys/constellation/debugd/coordinator"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd"
|
||||
depl "github.com/edgelesssys/constellation/debugd/debugd/deploy"
|
||||
pb "github.com/edgelesssys/constellation/debugd/service"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
configc "github.com/edgelesssys/constellation/internal/config"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
statec "github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
@ -105,7 +105,7 @@ type deployOnEndpointInput struct {
|
||||
debugdEndpoint string
|
||||
coordinatorPath string
|
||||
reader fileToStreamReader
|
||||
authorizedKeys []ssh.SSHKey
|
||||
authorizedKeys []ssh.UserKey
|
||||
systemdUnits []depl.SystemdUnit
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ func deployOnEndpoint(ctx context.Context, in deployOnEndpointInput) error {
|
||||
for _, key := range in.authorizedKeys {
|
||||
pbKeys = append(pbKeys, &pb.AuthorizedKey{
|
||||
Username: key.Username,
|
||||
KeyValue: key.KeyValue,
|
||||
KeyValue: key.PublicKey,
|
||||
})
|
||||
}
|
||||
authorizedKeysResponse, err := client.UploadAuthorizedKeys(ctx, &pb.UploadAuthorizedKeysRequest{Keys: pbKeys}, grpc.WaitForReady(true))
|
||||
|
@ -5,9 +5,9 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
)
|
||||
|
||||
// CDBGConfig describes the constellation-cli config file.
|
||||
@ -17,7 +17,7 @@ type CDBGConfig struct {
|
||||
|
||||
// ConstellationDebugdConfig is the cdbg specific configuration.
|
||||
type ConstellationDebugdConfig struct {
|
||||
AuthorizedKeys []ssh.SSHKey `yaml:"authorizedKeys"`
|
||||
AuthorizedKeys []ssh.UserKey `yaml:"authorizedKeys"`
|
||||
CoordinatorPath string `yaml:"coordinatorPath"`
|
||||
SystemdUnits []deploy.SystemdUnit `yaml:"systemdUnits,omitempty"`
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/metadata/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/metadata/fallback"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/server"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/spf13/afero"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
@ -20,9 +22,10 @@ import (
|
||||
func main() {
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
streamer := coordinator.NewFileStreamer(afero.NewOsFs())
|
||||
fs := afero.NewOsFs()
|
||||
streamer := coordinator.NewFileStreamer(fs)
|
||||
serviceManager := deploy.NewServiceManager()
|
||||
ssh := deploy.NewSSHAccess(afero.NewOsFs())
|
||||
ssh := ssh.NewSSHAccess(user.NewLinuxUserManager(fs))
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
@ -1,84 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy/createuser"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy/passwd"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
// ErrUserDoesNotExist is returned by GetLinuxUser if a linux user does not exist yet.
|
||||
var ErrUserDoesNotExist = errors.New("user does not exist")
|
||||
|
||||
type passwdParser interface {
|
||||
Parse(fs afero.Fs) (passwd.Entries, error)
|
||||
}
|
||||
|
||||
type userCreator interface {
|
||||
CreateUser(ctx context.Context, username string) error
|
||||
}
|
||||
|
||||
// LinuxUser holds relevant information about a linux user (subset of /etc/passwd).
|
||||
type LinuxUser struct {
|
||||
Username string
|
||||
Home string
|
||||
Uid int
|
||||
Gid int
|
||||
}
|
||||
|
||||
// LinuxUserManager can retrieve information on linux users and create new users.
|
||||
type LinuxUserManager struct {
|
||||
fs afero.Fs
|
||||
passwd passwdParser
|
||||
creator userCreator
|
||||
}
|
||||
|
||||
// NewLinuxUserManager creates a new LinuxUserManager.
|
||||
func NewLinuxUserManager(fs afero.Fs) *LinuxUserManager {
|
||||
return &LinuxUserManager{
|
||||
fs: fs,
|
||||
passwd: passwd.Passwd{},
|
||||
creator: createuser.Unix{},
|
||||
}
|
||||
}
|
||||
|
||||
// getLinuxUser tries to find an existing linux user in /etc/passwd.
|
||||
func (l *LinuxUserManager) getLinuxUser(username string) (LinuxUser, error) {
|
||||
entries, err := l.passwd.Parse(l.fs)
|
||||
if err != nil {
|
||||
return LinuxUser{}, err
|
||||
}
|
||||
if _, ok := entries[username]; !ok {
|
||||
return LinuxUser{}, ErrUserDoesNotExist
|
||||
}
|
||||
entry := entries[username]
|
||||
uid, err := strconv.Atoi(entry.Uid)
|
||||
if err != nil {
|
||||
return LinuxUser{}, fmt.Errorf("failed to parse users uid: %w", err)
|
||||
}
|
||||
gid, err := strconv.Atoi(entry.Gid)
|
||||
if err != nil {
|
||||
return LinuxUser{}, fmt.Errorf("failed to parse users gid: %w", err)
|
||||
}
|
||||
return LinuxUser{
|
||||
Username: username,
|
||||
Home: entry.Home,
|
||||
Uid: uid,
|
||||
Gid: gid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EnsureLinuxUserExists will try to create the user specified by username and call GetLinuxUser to retrieve user information.
|
||||
func (l *LinuxUserManager) EnsureLinuxUserExists(ctx context.Context, username string) (LinuxUser, error) {
|
||||
// try to create user (even if it already exists)
|
||||
if err := l.creator.CreateUser(ctx, username); err != nil {
|
||||
return LinuxUser{}, err
|
||||
}
|
||||
|
||||
return l.getLinuxUser(username)
|
||||
}
|
@ -7,7 +7,7 @@ import (
|
||||
azurecloud "github.com/edgelesssys/constellation/coordinator/cloudprovider/azure"
|
||||
gcpcloud "github.com/edgelesssys/constellation/coordinator/cloudprovider/gcp"
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
)
|
||||
|
||||
type providerMetadata interface {
|
||||
@ -72,16 +72,16 @@ func (f *Fetcher) DiscoverDebugdIPs(ctx context.Context) ([]string, error) {
|
||||
}
|
||||
|
||||
// FetchSSHKeys will query the metadata of the current instance and deploys any SSH keys found.
|
||||
func (f *Fetcher) FetchSSHKeys(ctx context.Context) ([]ssh.SSHKey, error) {
|
||||
func (f *Fetcher) FetchSSHKeys(ctx context.Context) ([]ssh.UserKey, error) {
|
||||
self, err := f.metaAPI.Self(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("retrieving ssh keys from cloud provider metadata failed: %w", err)
|
||||
}
|
||||
|
||||
keys := []ssh.SSHKey{}
|
||||
keys := []ssh.UserKey{}
|
||||
for username, userKeys := range self.SSHKeys {
|
||||
for _, keyValue := range userKeys {
|
||||
keys = append(keys, ssh.SSHKey{Username: username, KeyValue: keyValue})
|
||||
keys = append(keys, ssh.UserKey{Username: username, PublicKey: keyValue})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -70,7 +70,7 @@ func TestFetchSSHKeys(t *testing.T) {
|
||||
|
||||
testCases := map[string]struct {
|
||||
meta stubMetadata
|
||||
wantKeys []ssh.SSHKey
|
||||
wantKeys []ssh.UserKey
|
||||
wantErr bool
|
||||
}{
|
||||
"fetch works": {
|
||||
@ -81,10 +81,10 @@ func TestFetchSSHKeys(t *testing.T) {
|
||||
SSHKeys: map[string][]string{"bob": {"ssh-rsa bobskey"}},
|
||||
},
|
||||
},
|
||||
wantKeys: []ssh.SSHKey{
|
||||
wantKeys: []ssh.UserKey{
|
||||
{
|
||||
Username: "bob",
|
||||
KeyValue: "ssh-rsa bobskey",
|
||||
Username: "bob",
|
||||
PublicKey: "ssh-rsa bobskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ package fallback
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
)
|
||||
|
||||
// Fetcher implements metadata.Fetcher interface but does not actually fetch cloud provider metadata.
|
||||
@ -14,7 +14,7 @@ func (f Fetcher) DiscoverDebugdIPs(ctx context.Context) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f Fetcher) FetchSSHKeys(ctx context.Context) ([]ssh.SSHKey, error) {
|
||||
func (f Fetcher) FetchSSHKeys(ctx context.Context) ([]ssh.UserKey, error) {
|
||||
// Fallback fetcher does not try to fetch ssh keys
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/debugd"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
)
|
||||
|
||||
// Fetcher retrieves other debugd IPs and SSH keys from cloud provider metadata.
|
||||
type Fetcher interface {
|
||||
DiscoverDebugdIPs(ctx context.Context) ([]string, error)
|
||||
FetchSSHKeys(ctx context.Context) ([]ssh.SSHKey, error)
|
||||
FetchSSHKeys(ctx context.Context) ([]ssh.UserKey, error)
|
||||
}
|
||||
|
||||
// Scheduler schedules fetching of metadata using timers.
|
||||
@ -122,7 +122,7 @@ func (s *Scheduler) downloadCoordinator(ctx context.Context, ips []string) (succ
|
||||
}
|
||||
|
||||
// deploySSHKeys tries to deploy a list of SSH keys and logs errors encountered.
|
||||
func (s *Scheduler) deploySSHKeys(ctx context.Context, keys []ssh.SSHKey) {
|
||||
func (s *Scheduler) deploySSHKeys(ctx context.Context, keys []ssh.UserKey) {
|
||||
for _, key := range keys {
|
||||
err := s.ssh.DeploySSHAuthorizedKey(ctx, key)
|
||||
if err != nil {
|
||||
@ -137,5 +137,5 @@ type downloader interface {
|
||||
}
|
||||
|
||||
type sshDeployer interface {
|
||||
DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.SSHKey) error
|
||||
DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.UserKey) error
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -17,23 +17,23 @@ func TestSchedulerStart(t *testing.T) {
|
||||
ssh stubSSHDeployer
|
||||
downloader stubDownloader
|
||||
timeout time.Duration
|
||||
wantSSHKeys []ssh.SSHKey
|
||||
wantSSHKeys []ssh.UserKey
|
||||
wantDebugdDownloads []string
|
||||
}{
|
||||
"scheduler works and calls fetcher functions at least once": {},
|
||||
"ssh keys are fetched": {
|
||||
fetcher: stubFetcher{
|
||||
keys: []ssh.SSHKey{
|
||||
keys: []ssh.UserKey{
|
||||
{
|
||||
Username: "test",
|
||||
KeyValue: "testkey",
|
||||
Username: "test",
|
||||
PublicKey: "testkey",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantSSHKeys: []ssh.SSHKey{
|
||||
wantSSHKeys: []ssh.UserKey{
|
||||
{
|
||||
Username: "test",
|
||||
KeyValue: "testkey",
|
||||
Username: "test",
|
||||
PublicKey: "testkey",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -95,7 +95,7 @@ type stubFetcher struct {
|
||||
fetchSSHKeysCalls int
|
||||
|
||||
ips []string
|
||||
keys []ssh.SSHKey
|
||||
keys []ssh.UserKey
|
||||
discoverErr error
|
||||
fetchSSHKeysErr error
|
||||
}
|
||||
@ -105,18 +105,18 @@ func (s *stubFetcher) DiscoverDebugdIPs(ctx context.Context) ([]string, error) {
|
||||
return s.ips, s.discoverErr
|
||||
}
|
||||
|
||||
func (s *stubFetcher) FetchSSHKeys(ctx context.Context) ([]ssh.SSHKey, error) {
|
||||
func (s *stubFetcher) FetchSSHKeys(ctx context.Context) ([]ssh.UserKey, error) {
|
||||
s.fetchSSHKeysCalls++
|
||||
return s.keys, s.fetchSSHKeysErr
|
||||
}
|
||||
|
||||
type stubSSHDeployer struct {
|
||||
sshKeys []ssh.SSHKey
|
||||
sshKeys []ssh.UserKey
|
||||
|
||||
deployErr error
|
||||
}
|
||||
|
||||
func (s *stubSSHDeployer) DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.SSHKey) error {
|
||||
func (s *stubSSHDeployer) DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.UserKey) error {
|
||||
s.sshKeys = append(s.sshKeys, sshKey)
|
||||
|
||||
return s.deployErr
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/debugd/debugd"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy"
|
||||
pb "github.com/edgelesssys/constellation/debugd/service"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@ -37,7 +37,7 @@ func New(ssh sshDeployer, serviceManager serviceManager, streamer streamer) pb.D
|
||||
func (s *debugdServer) UploadAuthorizedKeys(ctx context.Context, in *pb.UploadAuthorizedKeysRequest) (*pb.UploadAuthorizedKeysResponse, error) {
|
||||
log.Println("Uploading authorized keys")
|
||||
for _, key := range in.Keys {
|
||||
if err := s.ssh.DeploySSHAuthorizedKey(ctx, ssh.SSHKey{Username: key.Username, KeyValue: key.KeyValue}); err != nil {
|
||||
if err := s.ssh.DeploySSHAuthorizedKey(ctx, ssh.UserKey{Username: key.Username, PublicKey: key.KeyValue}); err != nil {
|
||||
log.Printf("Uploading authorized keys failed: %v\n", err)
|
||||
return &pb.UploadAuthorizedKeysResponse{
|
||||
Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
|
||||
@ -117,7 +117,7 @@ func Start(wg *sync.WaitGroup, serv pb.DebugdServer) {
|
||||
}
|
||||
|
||||
type sshDeployer interface {
|
||||
DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.SSHKey) error
|
||||
DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.UserKey) error
|
||||
}
|
||||
|
||||
type serviceManager interface {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/debugd/coordinator"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy"
|
||||
pb "github.com/edgelesssys/constellation/debugd/service"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
@ -28,7 +28,7 @@ func TestUploadAuthorizedKeys(t *testing.T) {
|
||||
request *pb.UploadAuthorizedKeysRequest
|
||||
wantErr bool
|
||||
wantResponseStatus pb.UploadAuthorizedKeysStatus
|
||||
wantKeys []ssh.SSHKey
|
||||
wantKeys []ssh.UserKey
|
||||
}{
|
||||
"upload authorized keys works": {
|
||||
request: &pb.UploadAuthorizedKeysRequest{
|
||||
@ -40,10 +40,10 @@ func TestUploadAuthorizedKeys(t *testing.T) {
|
||||
},
|
||||
},
|
||||
wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
|
||||
wantKeys: []ssh.SSHKey{
|
||||
wantKeys: []ssh.UserKey{
|
||||
{
|
||||
Username: "testuser",
|
||||
KeyValue: "teskey",
|
||||
Username: "testuser",
|
||||
PublicKey: "teskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -58,10 +58,10 @@ func TestUploadAuthorizedKeys(t *testing.T) {
|
||||
},
|
||||
ssh: stubSSHDeployer{deployErr: errors.New("ssh key deployment error")},
|
||||
wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
|
||||
wantKeys: []ssh.SSHKey{
|
||||
wantKeys: []ssh.UserKey{
|
||||
{
|
||||
Username: "testuser",
|
||||
KeyValue: "teskey",
|
||||
Username: "testuser",
|
||||
PublicKey: "teskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -323,12 +323,12 @@ func TestUploadSystemServiceUnits(t *testing.T) {
|
||||
}
|
||||
|
||||
type stubSSHDeployer struct {
|
||||
sshKeys []ssh.SSHKey
|
||||
sshKeys []ssh.UserKey
|
||||
|
||||
deployErr error
|
||||
}
|
||||
|
||||
func (s *stubSSHDeployer) DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.SSHKey) error {
|
||||
func (s *stubSSHDeployer) DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.UserKey) error {
|
||||
s.sshKeys = append(s.sshKeys, sshKey)
|
||||
|
||||
return s.deployErr
|
||||
|
@ -1,7 +0,0 @@
|
||||
package ssh
|
||||
|
||||
// SSHKey describes a public ssh key.
|
||||
type SSHKey struct {
|
||||
Username string `yaml:"user"`
|
||||
KeyValue string `yaml:"pubkey"`
|
||||
}
|
@ -9,10 +9,11 @@ import (
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
awsClient "github.com/edgelesssys/constellation/cli/ec2/client"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
gcpClient "github.com/edgelesssys/constellation/cli/gcp/client"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@ -46,6 +47,7 @@ type Config struct {
|
||||
AutoscalingNodeGroupsMax *int `yaml:"autoscalingNodeGroupsMax,omitempty"`
|
||||
StateDiskSizeGB *int `yaml:"StateDisksizeGB,omitempty"`
|
||||
Provider *ProviderConfig `yaml:"provider,omitempty"`
|
||||
SSHUsers []*ssh.UserKey `yaml:"sshUsers,omitempty"`
|
||||
}
|
||||
|
||||
// Default returns a struct with the default config.
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/cli/gcp/client"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
44
internal/deploy/ssh/proto.go
Normal file
44
internal/deploy/ssh/proto.go
Normal file
@ -0,0 +1,44 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
)
|
||||
|
||||
// FromProtoSlice converts a SSH UserKey definition from pubproto to the Go flavor.
|
||||
func FromProtoSlice(input []*pubproto.SSHUserKey) []UserKey {
|
||||
if input == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
output := make([]UserKey, 0)
|
||||
|
||||
for _, pair := range input {
|
||||
singlePair := UserKey{
|
||||
Username: pair.Username,
|
||||
PublicKey: pair.PublicKey,
|
||||
}
|
||||
|
||||
output = append(output, singlePair)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// ToProtoSlice converts a SSH UserKey definition from Go to pubproto flavor.
|
||||
func ToProtoSlice(input []*UserKey) []*pubproto.SSHUserKey {
|
||||
if input == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
output := make([]*pubproto.SSHUserKey, 0)
|
||||
for _, pair := range input {
|
||||
singlePair := pubproto.SSHUserKey{
|
||||
Username: pair.Username,
|
||||
PublicKey: pair.PublicKey,
|
||||
}
|
||||
|
||||
output = append(output, &singlePair)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
36
internal/deploy/ssh/proto_test.go
Normal file
36
internal/deploy/ssh/proto_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToAndFromProtoSlice(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
DemoSSHUser1 := UserKey{
|
||||
Username: "test-user-2",
|
||||
PublicKey: "ssh-rsa abcdefg",
|
||||
}
|
||||
|
||||
DemoSSHUser2 := UserKey{
|
||||
Username: "test-user-2",
|
||||
PublicKey: "ssh-rsa hijklmnop",
|
||||
}
|
||||
|
||||
// Input usually consists of pointers (from config parsing)
|
||||
DemoSSHUsersPointers := make([]*UserKey, 0)
|
||||
DemoSSHUsersPointers = append(DemoSSHUsersPointers, &DemoSSHUser1)
|
||||
DemoSSHUsersPointers = append(DemoSSHUsersPointers, &DemoSSHUser2)
|
||||
|
||||
// Expected output usually does not consist of pointers
|
||||
DemoSSHUsersNoPointers := make([]UserKey, 0)
|
||||
DemoSSHUsersNoPointers = append(DemoSSHUsersNoPointers, DemoSSHUser1)
|
||||
DemoSSHUsersNoPointers = append(DemoSSHUsersNoPointers, DemoSSHUser2)
|
||||
|
||||
ToProtoArray := ToProtoSlice(DemoSSHUsersPointers)
|
||||
FromProtoArray := FromProtoSlice(ToProtoArray)
|
||||
|
||||
assert.Equal(DemoSSHUsersNoPointers, FromProtoArray)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package deploy
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -7,46 +7,43 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy/createuser"
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy/passwd"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
)
|
||||
|
||||
// UserKey describes an user that should be created with a corresponding public SSH key.
|
||||
type UserKey struct {
|
||||
Username string `yaml:"user"`
|
||||
PublicKey string `yaml:"pubkey"`
|
||||
}
|
||||
|
||||
// SSHAccess reads ssh public keys from a channel, creates the specified users if required and writes the public keys to the users authorized_keys file.
|
||||
type SSHAccess struct {
|
||||
fs afero.Fs
|
||||
userManager LinuxUserManager
|
||||
userManager user.LinuxUserManager
|
||||
authorized map[string]bool
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
||||
// NewSSHAccess creates a new SSHAccess.
|
||||
func NewSSHAccess(fs afero.Fs) *SSHAccess {
|
||||
func NewSSHAccess(userManager user.LinuxUserManager) *SSHAccess {
|
||||
return &SSHAccess{
|
||||
fs: fs,
|
||||
userManager: LinuxUserManager{
|
||||
fs: fs,
|
||||
passwd: passwd.Passwd{},
|
||||
creator: createuser.Unix{},
|
||||
},
|
||||
mux: sync.Mutex{},
|
||||
authorized: map[string]bool{},
|
||||
userManager: userManager,
|
||||
mux: sync.Mutex{},
|
||||
authorized: map[string]bool{},
|
||||
}
|
||||
}
|
||||
|
||||
// alreadyAuthorized checks if key was written to authorized keys before.
|
||||
func (s *SSHAccess) alreadyAuthorized(sshKey ssh.SSHKey) bool {
|
||||
_, ok := s.authorized[fmt.Sprintf("%s:%s", sshKey.Username, sshKey.KeyValue)]
|
||||
func (s *SSHAccess) alreadyAuthorized(sshKey UserKey) bool {
|
||||
_, ok := s.authorized[fmt.Sprintf("%s:%s", sshKey.Username, sshKey.PublicKey)]
|
||||
return ok
|
||||
}
|
||||
|
||||
// rememberAuthorized marks this key as already written to authorized keys..
|
||||
func (s *SSHAccess) rememberAuthorized(sshKey ssh.SSHKey) {
|
||||
s.authorized[fmt.Sprintf("%s:%s", sshKey.Username, sshKey.KeyValue)] = true
|
||||
func (s *SSHAccess) rememberAuthorized(sshKey UserKey) {
|
||||
s.authorized[fmt.Sprintf("%s:%s", sshKey.Username, sshKey.PublicKey)] = true
|
||||
}
|
||||
|
||||
func (s *SSHAccess) DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.SSHKey) error {
|
||||
func (s *SSHAccess) DeploySSHAuthorizedKey(ctx context.Context, sshKey UserKey) error {
|
||||
// allow only one thread to write to authorized keys, create users and update the authorized map at a time
|
||||
s.mux.Lock()
|
||||
defer s.mux.Unlock()
|
||||
@ -61,31 +58,31 @@ func (s *SSHAccess) DeploySSHAuthorizedKey(ctx context.Context, sshKey ssh.SSHKe
|
||||
// CoreOS uses https://github.com/coreos/ssh-key-dir to search for ssh keys in ~/.ssh/authorized_keys.d/*
|
||||
sshFolder := fmt.Sprintf("%s/.ssh", user.Home)
|
||||
authorized_keys_d := fmt.Sprintf("%s/authorized_keys.d", sshFolder)
|
||||
if err := s.fs.MkdirAll(authorized_keys_d, 0o700); err != nil {
|
||||
if err := s.userManager.Fs.MkdirAll(authorized_keys_d, 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.fs.Chown(sshFolder, user.Uid, user.Gid); err != nil {
|
||||
if err := s.userManager.Fs.Chown(sshFolder, user.Uid, user.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.fs.Chown(authorized_keys_d, user.Uid, user.Gid); err != nil {
|
||||
if err := s.userManager.Fs.Chown(authorized_keys_d, user.Uid, user.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
authorizedKeysPath := fmt.Sprintf("%s/debugd", authorized_keys_d)
|
||||
authorizedKeysFile, err := s.fs.OpenFile(authorizedKeysPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
authorizedKeysPath := fmt.Sprintf("%s/ssh-keys", authorized_keys_d)
|
||||
authorizedKeysFile, err := s.userManager.Fs.OpenFile(authorizedKeysPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = authorizedKeysFile.WriteString(fmt.Sprintf("%s %s\n", sshKey.KeyValue, sshKey.Username))
|
||||
_, err = authorizedKeysFile.WriteString(fmt.Sprintf("%s %s\n", sshKey.PublicKey, sshKey.Username))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := authorizedKeysFile.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.fs.Chown(authorizedKeysPath, user.Uid, user.Gid); err != nil {
|
||||
if err := s.userManager.Fs.Chown(authorizedKeysPath, user.Uid, user.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.fs.Chmod(authorizedKeysPath, 0o644); err != nil {
|
||||
if err := s.userManager.Fs.Chmod(authorizedKeysPath, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
s.rememberAuthorized(sshKey)
|
@ -1,26 +1,24 @@
|
||||
package deploy
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy/passwd"
|
||||
"github.com/edgelesssys/constellation/debugd/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/user"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDeploySSHAuthorizedKey(t *testing.T) {
|
||||
authorizedKey := ssh.SSHKey{
|
||||
Username: "user",
|
||||
KeyValue: "ssh-rsa testkey",
|
||||
authorizedKey := UserKey{
|
||||
Username: "user",
|
||||
PublicKey: "ssh-rsa testkey",
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
fs afero.Fs
|
||||
userCreator *stubUserCreator
|
||||
passwdContents string
|
||||
alreadyDeployed bool
|
||||
readonly bool
|
||||
@ -30,40 +28,26 @@ func TestDeploySSHAuthorizedKey(t *testing.T) {
|
||||
}{
|
||||
"deploy works": {
|
||||
fs: afero.NewMemMapFs(),
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
wantErr: false,
|
||||
wantFile: true,
|
||||
wantFileContents: "ssh-rsa testkey user\n",
|
||||
},
|
||||
"appending ssh key works": {
|
||||
fs: memMapFsWithFile("/home/user/.ssh/authorized_keys.d/debugd", "ssh-rsa preexistingkey user\n"),
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
fs: memMapFsWithFile("/home/user/.ssh/authorized_keys.d/ssh-keys", "ssh-rsa preexistingkey user\n"),
|
||||
wantErr: false,
|
||||
wantFile: true,
|
||||
wantFileContents: "ssh-rsa preexistingkey user\nssh-rsa testkey user\n",
|
||||
},
|
||||
"redeployment avoided": {
|
||||
fs: afero.NewMemMapFs(),
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
wantErr: false,
|
||||
alreadyDeployed: true,
|
||||
wantFile: false,
|
||||
},
|
||||
"user does not exist": {
|
||||
fs: afero.NewMemMapFs(),
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "",
|
||||
wantErr: true,
|
||||
},
|
||||
"readonly fs": {
|
||||
fs: afero.NewMemMapFs(),
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
readonly: true,
|
||||
wantErr: true,
|
||||
fs: afero.NewMemMapFs(),
|
||||
readonly: true,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -71,24 +55,20 @@ func TestDeploySSHAuthorizedKey(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
userManager := user.NewLinuxUserManagerFake(tc.fs)
|
||||
|
||||
assert.NoError(afero.WriteFile(tc.fs, "/etc/passwd", []byte(tc.passwdContents), 0o755))
|
||||
assert.NoError(afero.WriteFile(userManager.Fs, "/etc/passwd", []byte(tc.passwdContents), 0o755))
|
||||
if tc.readonly {
|
||||
tc.fs = afero.NewReadOnlyFs(tc.fs)
|
||||
userManager.Fs = afero.NewReadOnlyFs(userManager.Fs)
|
||||
}
|
||||
authorized := map[string]bool{}
|
||||
if tc.alreadyDeployed {
|
||||
authorized["user:ssh-rsa testkey"] = true
|
||||
}
|
||||
sshAccess := SSHAccess{
|
||||
fs: tc.fs,
|
||||
userManager: LinuxUserManager{
|
||||
fs: tc.fs,
|
||||
passwd: passwd.Passwd{},
|
||||
creator: tc.userCreator,
|
||||
},
|
||||
mux: sync.Mutex{},
|
||||
authorized: authorized,
|
||||
userManager: userManager,
|
||||
mux: sync.Mutex{},
|
||||
authorized: authorized,
|
||||
}
|
||||
err := sshAccess.DeploySSHAuthorizedKey(context.Background(), authorizedKey)
|
||||
|
||||
@ -98,11 +78,11 @@ func TestDeploySSHAuthorizedKey(t *testing.T) {
|
||||
}
|
||||
require.NoError(err)
|
||||
if tc.wantFile {
|
||||
fileContents, err := afero.ReadFile(tc.fs, "/home/user/.ssh/authorized_keys.d/debugd")
|
||||
fileContents, err := afero.ReadFile(userManager.Fs, "/home/user/.ssh/authorized_keys.d/ssh-keys")
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantFileContents, string(fileContents))
|
||||
} else {
|
||||
exists, err := afero.Exists(tc.fs, "/home/user/.ssh/authorized_keys.d/debugd")
|
||||
exists, err := afero.Exists(userManager.Fs, "/home/user/.ssh/authorized_keys.d/ssh-keys")
|
||||
assert.NoError(err)
|
||||
assert.False(exists)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package createuser
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
147
internal/deploy/user/linux_user.go
Normal file
147
internal/deploy/user/linux_user.go
Normal file
@ -0,0 +1,147 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
// ErrUserDoesNotExist is returned by GetLinuxUser if a linux user does not exist yet.
|
||||
var ErrUserDoesNotExist = errors.New("user does not exist")
|
||||
|
||||
type passwdParser interface {
|
||||
Parse(fs afero.Fs) (Entries, error)
|
||||
}
|
||||
|
||||
type userCreator interface {
|
||||
CreateUser(ctx context.Context, username string) error
|
||||
}
|
||||
|
||||
// LinuxUser holds relevant information about a linux user (subset of /etc/passwd).
|
||||
type LinuxUser struct {
|
||||
Username string
|
||||
Home string
|
||||
Uid int
|
||||
Gid int
|
||||
}
|
||||
|
||||
// LinuxUserManager can retrieve information on linux users and create new users.
|
||||
type LinuxUserManager struct {
|
||||
Fs afero.Fs
|
||||
Passwd passwdParser
|
||||
Creator userCreator
|
||||
}
|
||||
|
||||
// NewLinuxUserManager creates a new LinuxUserManager.
|
||||
func NewLinuxUserManager(fs afero.Fs) LinuxUserManager {
|
||||
return LinuxUserManager{
|
||||
Fs: fs,
|
||||
Passwd: Passwd{},
|
||||
Creator: Unix{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewLinuxUserManagerFake creates a new LinuxUserManager that is used for unit tests.
|
||||
func NewLinuxUserManagerFake(fs afero.Fs) LinuxUserManager {
|
||||
return LinuxUserManager{
|
||||
Fs: fs,
|
||||
Passwd: Passwd{},
|
||||
Creator: &StubUserCreator{fs: fs},
|
||||
}
|
||||
}
|
||||
|
||||
// StubUserCreator is used for unit tests.
|
||||
type StubUserCreator struct {
|
||||
fs afero.Fs
|
||||
usernames []string
|
||||
createUserErr error
|
||||
currentUID int
|
||||
}
|
||||
|
||||
func (s *StubUserCreator) CreateUser(ctx context.Context, username string) error {
|
||||
if stringInSlice(username, s.usernames) {
|
||||
return errors.New("username already exists")
|
||||
}
|
||||
|
||||
// We want created users to start at UID 1000
|
||||
if s.currentUID == 0 {
|
||||
s.currentUID = 1000
|
||||
}
|
||||
|
||||
if s.createUserErr != nil {
|
||||
return s.createUserErr
|
||||
}
|
||||
|
||||
// If no predefined error is supposed to happen, increase the UID (unless the file system code fails)
|
||||
if s.fs != nil {
|
||||
lineToWrite := fmt.Sprintf("%s:x:%d:%d:%s:/home/%s:/bin/bash\n", username, s.currentUID, s.currentUID, username, username)
|
||||
file, err := s.fs.OpenFile("/etc/passwd", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
n, err := file.WriteString(lineToWrite)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if n != len(lineToWrite) {
|
||||
return errors.New("written text too short")
|
||||
}
|
||||
}
|
||||
|
||||
s.currentUID += 1
|
||||
s.usernames = append(s.usernames, username)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getLinuxUser tries to find an existing linux user in /etc/passwd.
|
||||
func (l *LinuxUserManager) getLinuxUser(username string) (LinuxUser, error) {
|
||||
entries, err := l.Passwd.Parse(l.Fs)
|
||||
if err != nil {
|
||||
return LinuxUser{}, err
|
||||
}
|
||||
if _, ok := entries[username]; !ok {
|
||||
return LinuxUser{}, ErrUserDoesNotExist
|
||||
}
|
||||
entry := entries[username]
|
||||
uid, err := strconv.Atoi(entry.Uid)
|
||||
if err != nil {
|
||||
return LinuxUser{}, fmt.Errorf("failed to parse users uid: %w", err)
|
||||
}
|
||||
gid, err := strconv.Atoi(entry.Gid)
|
||||
if err != nil {
|
||||
return LinuxUser{}, fmt.Errorf("failed to parse users gid: %w", err)
|
||||
}
|
||||
return LinuxUser{
|
||||
Username: username,
|
||||
Home: entry.Home,
|
||||
Uid: uid,
|
||||
Gid: gid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EnsureLinuxUserExists will try to create the user specified by username and call GetLinuxUser to retrieve user information.
|
||||
func (l *LinuxUserManager) EnsureLinuxUserExists(ctx context.Context, username string) (LinuxUser, error) {
|
||||
// try to create user (even if it already exists)
|
||||
if err := l.Creator.CreateUser(ctx, username); err != nil {
|
||||
return LinuxUser{}, err
|
||||
}
|
||||
|
||||
return l.getLinuxUser(username)
|
||||
}
|
||||
|
||||
// stringInSlice checks if a given string exists in a slice of strings.
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
package deploy
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/debugd/deploy/passwd"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -15,13 +14,11 @@ func TestGetLinuxUser(t *testing.T) {
|
||||
username := "user"
|
||||
|
||||
testCases := map[string]struct {
|
||||
userCreator *stubUserCreator
|
||||
passwdContents string
|
||||
wantErr bool
|
||||
wantUser LinuxUser
|
||||
}{
|
||||
"get works": {
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
wantErr: false,
|
||||
wantUser: LinuxUser{
|
||||
@ -32,22 +29,18 @@ func TestGetLinuxUser(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"user does not exist": {
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "",
|
||||
wantErr: true,
|
||||
},
|
||||
"parse fails": {
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "invalid contents\n",
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid uid": {
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:invalid:1000:user:/home/user:/bin/bash\n",
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid gid": {
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:invalid:user:/home/user:/bin/bash\n",
|
||||
wantErr: true,
|
||||
},
|
||||
@ -60,11 +53,7 @@ func TestGetLinuxUser(t *testing.T) {
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
assert.NoError(afero.WriteFile(fs, "/etc/passwd", []byte(tc.passwdContents), 0o755))
|
||||
manager := LinuxUserManager{
|
||||
fs: fs,
|
||||
passwd: passwd.Passwd{},
|
||||
creator: tc.userCreator,
|
||||
}
|
||||
manager := NewLinuxUserManagerFake(fs)
|
||||
user, err := manager.getLinuxUser(username)
|
||||
|
||||
if tc.wantErr {
|
||||
@ -81,15 +70,13 @@ func TestEnsureLinuxUserExists(t *testing.T) {
|
||||
username := "user"
|
||||
|
||||
testCases := map[string]struct {
|
||||
userCreator *stubUserCreator
|
||||
passwdContents string
|
||||
wantErr bool
|
||||
wantUser LinuxUser
|
||||
userCreator *StubUserCreator
|
||||
wantErr bool
|
||||
wantUser LinuxUser
|
||||
}{
|
||||
"create works": {
|
||||
userCreator: &stubUserCreator{},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
wantErr: false,
|
||||
userCreator: &StubUserCreator{},
|
||||
wantErr: false,
|
||||
wantUser: LinuxUser{
|
||||
Username: "user",
|
||||
Home: "/home/user",
|
||||
@ -98,11 +85,10 @@ func TestEnsureLinuxUserExists(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"create fails": {
|
||||
userCreator: &stubUserCreator{
|
||||
userCreator: &StubUserCreator{
|
||||
createUserErr: errors.New("create fails"),
|
||||
},
|
||||
passwdContents: "user:x:1000:1000:user:/home/user:/bin/bash\n",
|
||||
wantErr: true,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -112,12 +98,9 @@ func TestEnsureLinuxUserExists(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
assert.NoError(afero.WriteFile(fs, "/etc/passwd", []byte(tc.passwdContents), 0o755))
|
||||
manager := LinuxUserManager{
|
||||
fs: fs,
|
||||
passwd: passwd.Passwd{},
|
||||
creator: tc.userCreator,
|
||||
}
|
||||
manager := NewLinuxUserManagerFake(fs)
|
||||
tc.userCreator.fs = fs
|
||||
manager.Creator = tc.userCreator
|
||||
user, err := manager.EnsureLinuxUserExists(context.Background(), username)
|
||||
|
||||
if tc.wantErr {
|
||||
@ -131,12 +114,10 @@ func TestEnsureLinuxUserExists(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type stubUserCreator struct {
|
||||
usernames []string
|
||||
createUserErr error
|
||||
}
|
||||
func TestStringInSlice(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testSlice := []string{"abc", "efg", "xyz"}
|
||||
|
||||
func (s *stubUserCreator) CreateUser(ctx context.Context, username string) error {
|
||||
s.usernames = append(s.usernames, username)
|
||||
return s.createUserErr
|
||||
assert.True(stringInSlice("efg", testSlice))
|
||||
assert.False(stringInSlice("hij", testSlice))
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package passwd
|
||||
package user
|
||||
|
||||
import (
|
||||
"github.com/spf13/afero"
|
@ -1,4 +1,4 @@
|
||||
package passwd
|
||||
package user
|
||||
|
||||
import (
|
||||
"testing"
|
@ -9,10 +9,10 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/config"
|
||||
"github.com/edgelesssys/constellation/coordinator/nodestate"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/file"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/config"
|
||||
"github.com/edgelesssys/constellation/coordinator/nodestate"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
Loading…
Reference in New Issue
Block a user