Disable SSH key deployment with debugd / cdbg

This commit is contained in:
Malte Poll 2022-10-20 09:56:45 +02:00 committed by Malte Poll
parent b57b25fdaa
commit 6a1405f7c9
5 changed files with 158 additions and 135 deletions

View File

@ -117,20 +117,24 @@ func deployOnEndpoint(ctx context.Context, in deployOnEndpointInput) error {
defer conn.Close()
client := pb.NewDebugdClient(conn)
log.Println("Uploading authorized keys")
pbKeys := []*pb.AuthorizedKey{}
for _, key := range in.authorizedKeys {
pbKeys = append(pbKeys, &pb.AuthorizedKey{
Username: key.Username,
KeyValue: key.PublicKey,
})
}
authorizedKeysResponse, err := client.UploadAuthorizedKeys(ctx, &pb.UploadAuthorizedKeysRequest{Keys: pbKeys}, grpc.WaitForReady(true))
if err != nil || authorizedKeysResponse.Status != pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS {
return fmt.Errorf("uploading authorized keys to instance %v failed: %v / %w", in.debugdEndpoint, authorizedKeysResponse, err)
if len(in.authorizedKeys) > 0 {
log.Println("Warning: Uploading authorized keys is currently disabled.")
}
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs.
// log.Println("Uploading authorized keys")
// pbKeys := []*pb.AuthorizedKey{}
// for _, key := range in.authorizedKeys {
// pbKeys = append(pbKeys, &pb.AuthorizedKey{
// Username: key.Username,
// KeyValue: key.PublicKey,
// })
// }
// authorizedKeysResponse, err := client.UploadAuthorizedKeys(ctx, &pb.UploadAuthorizedKeysRequest{Keys: pbKeys}, grpc.WaitForReady(true))
// if err != nil || authorizedKeysResponse.Status != pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS {
// return fmt.Errorf("uploading authorized keys to instance %v failed: %v / %w", in.debugdEndpoint, authorizedKeysResponse, err)
// }
stream, err := client.UploadBootstrapper(ctx)
stream, err := client.UploadBootstrapper(ctx, grpc.WaitForReady(true))
if err != nil {
return fmt.Errorf("starting bootstrapper upload to instance %v: %w", in.debugdEndpoint, err)
}

View File

@ -50,9 +50,11 @@ func NewScheduler(log *logger.Logger, fetcher Fetcher, ssh sshDeployer, download
func (s *Scheduler) Start(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
wg.Add(2)
wg.Add(1)
go s.discoveryLoop(ctx, wg)
go s.sshLoop(ctx, wg)
// TODO (stateless-ssh): re-enable once
// ssh keys can be deployed on readonly rootfs
// go s.sshLoop(ctx, wg)
}
// discoveryLoop discovers new debugd endpoints from cloud-provider metadata periodically.
@ -90,33 +92,35 @@ func (s *Scheduler) discoveryLoop(ctx context.Context, wg *sync.WaitGroup) {
}
// sshLoop discovers new ssh keys from cloud provider metadata periodically.
func (s *Scheduler) sshLoop(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs
// func (s *Scheduler) sshLoop(ctx context.Context, wg *sync.WaitGroup) {
// defer wg.Done()
ticker := time.NewTicker(debugd.SSHCheckInterval)
defer ticker.Stop()
for {
keys, err := s.fetcher.FetchSSHKeys(ctx)
if err != nil {
s.log.With(zap.Error(err)).Errorf("Fetching SSH keys failed")
} else {
s.deploySSHKeys(ctx, keys)
}
// ticker := time.NewTicker(debugd.SSHCheckInterval)
// defer ticker.Stop()
// for {
// keys, err := s.fetcher.FetchSSHKeys(ctx)
// if err != nil {
// s.log.With(zap.Error(err)).Errorf("Fetching SSH keys failed")
// } else {
// s.deploySSHKeys(ctx, keys)
// }
select {
case <-ticker.C:
case <-ctx.Done():
return
}
}
}
// select {
// case <-ticker.C:
// case <-ctx.Done():
// return
// }
// }
// }
// downloadDeployment tries to download deployment from a list of ips and logs errors encountered.
func (s *Scheduler) downloadDeployment(ctx context.Context, ips []string) (success bool) {
for _, ip := range ips {
keys, err := s.downloader.DownloadDeployment(ctx, ip)
_, err := s.downloader.DownloadDeployment(ctx, ip)
if err == nil {
s.deploySSHKeys(ctx, keys)
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs
// s.deploySSHKeys(ctx, keys)
return true
}
if errors.Is(err, fs.ErrExist) {
@ -129,16 +133,17 @@ func (s *Scheduler) downloadDeployment(ctx context.Context, ips []string) (succe
return false
}
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs
// deploySSHKeys tries to deploy a list of SSH keys and logs errors encountered.
func (s *Scheduler) deploySSHKeys(ctx context.Context, keys []ssh.UserKey) {
for _, key := range keys {
err := s.ssh.DeployAuthorizedKey(ctx, key)
if err != nil {
s.log.With(zap.Error(err), zap.Any("key", key)).Errorf("Deploying SSH key failed")
continue
}
}
}
// func (s *Scheduler) deploySSHKeys(ctx context.Context, keys []ssh.UserKey) {
// for _, key := range keys {
// err := s.ssh.DeployAuthorizedKey(ctx, key)
// if err != nil {
// s.log.With(zap.Error(err), zap.Any("key", key)).Errorf("Deploying SSH key failed")
// continue
// }
// }
// }
type downloader interface {
DownloadDeployment(ctx context.Context, ip string) ([]ssh.UserKey, error)

View File

@ -36,12 +36,13 @@ func TestSchedulerStart(t *testing.T) {
wantDebugdDownloads []string
}{
"scheduler works and calls fetcher functions at least once": {},
"ssh keys are fetched": {
fetcher: stubFetcher{
keys: []ssh.UserKey{{Username: "test", PublicKey: "testkey"}},
},
wantSSHKeys: []ssh.UserKey{{Username: "test", PublicKey: "testkey"}},
},
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs.
// "ssh keys are fetched": {
// fetcher: stubFetcher{
// keys: []ssh.UserKey{{Username: "test", PublicKey: "testkey"}},
// },
// wantSSHKeys: []ssh.UserKey{{Username: "test", PublicKey: "testkey"}},
// },
"download for discovered debugd ips is started": {
fetcher: stubFetcher{
ips: []string{"192.0.2.1", "192.0.2.2"},
@ -58,9 +59,10 @@ func TestSchedulerStart(t *testing.T) {
"endpoint discovery can fail": {
fetcher: stubFetcher{discoverErr: someErr},
},
"ssh key fetch can fail": {
fetcher: stubFetcher{fetchSSHKeysErr: someErr},
},
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs.
// "ssh key fetch can fail": {
// fetcher: stubFetcher{fetchSSHKeysErr: someErr},
// },
}
for name, tc := range testCases {
@ -80,10 +82,12 @@ func TestSchedulerStart(t *testing.T) {
go scheduler.Start(ctx, wg)
wg.Wait()
assert.Equal(tc.wantSSHKeys, tc.ssh.sshKeys)
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs.
// assert.Equal(tc.wantSSHKeys, tc.ssh.sshKeys)
assert.Equal(tc.wantDebugdDownloads, tc.downloader.ips)
assert.Greater(tc.fetcher.discoverCalls, 0)
assert.Greater(tc.fetcher.fetchSSHKeysCalls, 0)
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs.
// assert.Greater(tc.fetcher.fetchSSHKeysCalls, 0)
})
}
}

View File

@ -46,17 +46,27 @@ func New(log *logger.Logger, ssh sshDeployer, serviceManager serviceManager, str
}
}
// TODO (stateless-ssh): re-enable once ssh keys can be deployed on readonly rootfs.
// UploadAuthorizedKeys receives a list of authorized keys and forwards them to a channel.
//
// func (s *debugdServer) UploadAuthorizedKeys(ctx context.Context, in *pb.UploadAuthorizedKeysRequest) (*pb.UploadAuthorizedKeysResponse, error) {
// s.log.Infof("Uploading authorized keys")
// for _, key := range in.Keys {
// if err := s.ssh.DeployAuthorizedKey(ctx, ssh.UserKey{Username: key.Username, PublicKey: key.KeyValue}); err != nil {
// s.log.With(zap.Error(err)).Errorf("Uploading authorized keys failed")
// return &pb.UploadAuthorizedKeysResponse{
// Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
// }, nil
// }
// }
// return &pb.UploadAuthorizedKeysResponse{
// Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
// }, nil
// }
//
// UploadAuthorizedKeys receives a list of authorized keys and forwards them to a channel.
func (s *debugdServer) UploadAuthorizedKeys(ctx context.Context, in *pb.UploadAuthorizedKeysRequest) (*pb.UploadAuthorizedKeysResponse, error) {
s.log.Infof("Uploading authorized keys")
for _, key := range in.Keys {
if err := s.ssh.DeployAuthorizedKey(ctx, ssh.UserKey{Username: key.Username, PublicKey: key.KeyValue}); err != nil {
s.log.With(zap.Error(err)).Errorf("Uploading authorized keys failed")
return &pb.UploadAuthorizedKeysResponse{
Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
}, nil
}
}
s.log.Infof("Uploading authorized keys (Disabled feature)")
return &pb.UploadAuthorizedKeysResponse{
Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
}, nil

View File

@ -33,84 +33,84 @@ func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}
func TestUploadAuthorizedKeys(t *testing.T) {
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
// func TestUploadAuthorizedKeys(t *testing.T) {
// endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
testCases := map[string]struct {
ssh stubSSHDeployer
serviceManager stubServiceManager
request *pb.UploadAuthorizedKeysRequest
wantErr bool
wantResponseStatus pb.UploadAuthorizedKeysStatus
wantKeys []ssh.UserKey
}{
"upload authorized keys works": {
request: &pb.UploadAuthorizedKeysRequest{
Keys: []*pb.AuthorizedKey{
{
Username: "testuser",
KeyValue: "teskey",
},
},
},
wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
wantKeys: []ssh.UserKey{
{
Username: "testuser",
PublicKey: "teskey",
},
},
},
"deploy fails": {
request: &pb.UploadAuthorizedKeysRequest{
Keys: []*pb.AuthorizedKey{
{
Username: "testuser",
KeyValue: "teskey",
},
},
},
ssh: stubSSHDeployer{deployErr: errors.New("ssh key deployment error")},
wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
wantKeys: []ssh.UserKey{
{
Username: "testuser",
PublicKey: "teskey",
},
},
},
}
// testCases := map[string]struct {
// ssh stubSSHDeployer
// serviceManager stubServiceManager
// request *pb.UploadAuthorizedKeysRequest
// wantErr bool
// wantResponseStatus pb.UploadAuthorizedKeysStatus
// wantKeys []ssh.UserKey
// }{
// "upload authorized keys works": {
// request: &pb.UploadAuthorizedKeysRequest{
// Keys: []*pb.AuthorizedKey{
// {
// Username: "testuser",
// KeyValue: "teskey",
// },
// },
// },
// wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
// wantKeys: []ssh.UserKey{
// {
// Username: "testuser",
// PublicKey: "teskey",
// },
// },
// },
// "deploy fails": {
// request: &pb.UploadAuthorizedKeysRequest{
// Keys: []*pb.AuthorizedKey{
// {
// Username: "testuser",
// KeyValue: "teskey",
// },
// },
// },
// ssh: stubSSHDeployer{deployErr: errors.New("ssh key deployment error")},
// wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
// wantKeys: []ssh.UserKey{
// {
// Username: "testuser",
// PublicKey: "teskey",
// },
// },
// },
// }
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
// for name, tc := range testCases {
// t.Run(name, func(t *testing.T) {
// assert := assert.New(t)
// require := require.New(t)
serv := debugdServer{
log: logger.NewTest(t),
ssh: &tc.ssh,
serviceManager: &tc.serviceManager,
streamer: &fakeStreamer{},
}
// serv := debugdServer{
// log: logger.NewTest(t),
// ssh: &tc.ssh,
// serviceManager: &tc.serviceManager,
// streamer: &fakeStreamer{},
// }
grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
require.NoError(err)
defer conn.Close()
client := pb.NewDebugdClient(conn)
resp, err := client.UploadAuthorizedKeys(context.Background(), tc.request)
// grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
// require.NoError(err)
// defer conn.Close()
// client := pb.NewDebugdClient(conn)
// resp, err := client.UploadAuthorizedKeys(context.Background(), tc.request)
grpcServ.GracefulStop()
// grpcServ.GracefulStop()
if tc.wantErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.wantResponseStatus, resp.Status)
assert.ElementsMatch(tc.ssh.sshKeys, tc.wantKeys)
})
}
}
// if tc.wantErr {
// assert.Error(err)
// return
// }
// require.NoError(err)
// assert.Equal(tc.wantResponseStatus, resp.Status)
// assert.ElementsMatch(tc.ssh.sshKeys, tc.wantKeys)
// })
// }
// }
func TestUploadBootstrapper(t *testing.T) {
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)