From ac0d52b4c4c0d8f89f7c0f399bc92b1c39334fae Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Wed, 16 Oct 2024 15:15:15 +0100 Subject: [PATCH] UserTasks: Add SSM Document and Installer for DiscoverEC2 Issues This PR adds two new fields to the DiscoverEC2 User Task. SSM Document used to install teleport Teleport Installer script name used to install teleport This can be used to let the user know which scripts were used. For the SSM Document, users can then open it in webui. For the Installer Script, users can manage it using `tctl` client. --- .../go/teleport/usertasks/v1/user_tasks.pb.go | 89 ++++++++++++------- .../teleport/usertasks/v1/user_tasks.proto | 6 ++ api/types/usertasks/object.go | 14 ++- api/types/usertasks/object_test.go | 2 +- lib/srv/discovery/discovery.go | 10 ++- lib/srv/discovery/status.go | 30 ++++--- lib/srv/server/ssm_install.go | 20 +++++ lib/srv/server/ssm_install_test.go | 30 ++++--- 8 files changed, 138 insertions(+), 63 deletions(-) diff --git a/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go b/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go index 6e4362cf1943b..d24dcbae031c6 100644 --- a/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go +++ b/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go @@ -224,6 +224,12 @@ type DiscoverEC2 struct { AccountId string `protobuf:"bytes,2,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` // Region is the AWS Region where Teleport failed to enroll EC2 instances. Region string `protobuf:"bytes,3,opt,name=region,proto3" json:"region,omitempty"` + // SSMDocument is the Amazon Systems Manager SSM Document name that was used to install teleport on the instance. + // In Amazon console, the document is at: + // https://REGION.console.aws.amazon.com/systems-manager/documents/SSM_DOCUMENT/description + SsmDocument string `protobuf:"bytes,4,opt,name=ssm_document,json=ssmDocument,proto3" json:"ssm_document,omitempty"` + // InstallerScript is the Teleport installer script that was used to install teleport on the instance. + InstallerScript string `protobuf:"bytes,5,opt,name=installer_script,json=installerScript,proto3" json:"installer_script,omitempty"` } func (x *DiscoverEC2) Reset() { @@ -277,6 +283,20 @@ func (x *DiscoverEC2) GetRegion() string { return "" } +func (x *DiscoverEC2) GetSsmDocument() string { + if x != nil { + return x.SsmDocument + } + return "" +} + +func (x *DiscoverEC2) GetInstallerScript() string { + if x != nil { + return x.InstallerScript + } + return "" +} + // DiscoverEC2Instance contains the result of enrolling an AWS EC2 Instance. type DiscoverEC2Instance struct { state protoimpl.MessageState @@ -407,7 +427,7 @@ var file_teleport_usertasks_v1_user_tasks_proto_rawDesc = []byte{ 0x32, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x52, 0x0b, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x63, 0x32, 0x22, 0xff, 0x01, 0x0a, 0x0b, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x63, 0x32, 0x22, 0xcd, 0x02, 0x0a, 0x0b, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x12, 0x4f, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, @@ -417,37 +437,42 @@ var file_teleport_usertasks_v1_user_tasks_proto_rawDesc = []byte{ 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, - 0x1a, 0x68, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x40, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9e, 0x02, 0x0a, 0x13, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x29, - 0x0a, 0x10, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x12, 0x37, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, - 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x5f, 0x69, 0x64, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x56, 0x5a, 0x54, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, - 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, - 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, - 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x73, 0x6d, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x73, 0x6d, 0x44, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, + 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x1a, 0x68, + 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x40, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9e, 0x02, 0x0a, 0x13, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, + 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x29, 0x0a, 0x10, + 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x12, 0x37, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x08, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, + 0x04, 0x08, 0x04, 0x10, 0x05, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, + 0x64, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x42, 0x56, 0x5a, 0x54, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/proto/teleport/usertasks/v1/user_tasks.proto b/api/proto/teleport/usertasks/v1/user_tasks.proto index 81d8d52d17b63..d4a7a75e714fa 100644 --- a/api/proto/teleport/usertasks/v1/user_tasks.proto +++ b/api/proto/teleport/usertasks/v1/user_tasks.proto @@ -67,6 +67,12 @@ message DiscoverEC2 { string account_id = 2; // Region is the AWS Region where Teleport failed to enroll EC2 instances. string region = 3; + // SSMDocument is the Amazon Systems Manager SSM Document name that was used to install teleport on the instance. + // In Amazon console, the document is at: + // https://REGION.console.aws.amazon.com/systems-manager/documents/SSM_DOCUMENT/description + string ssm_document = 4; + // InstallerScript is the Teleport installer script that was used to install teleport on the instance. + string installer_script = 5; } // DiscoverEC2Instance contains the result of enrolling an AWS EC2 Instance. diff --git a/api/types/usertasks/object.go b/api/types/usertasks/object.go index 72a71fe05d259..244dda1d47bc1 100644 --- a/api/types/usertasks/object.go +++ b/api/types/usertasks/object.go @@ -215,10 +215,12 @@ func validateDiscoverEC2TaskType(ut *usertasksv1.UserTask) error { // TaskNameForDiscoverEC2Parts are the fields that deterministically compute a Discover EC2 task name. // To be used with TaskNameForDiscoverEC2 function. type TaskNameForDiscoverEC2Parts struct { - Integration string - IssueType string - AccountID string - Region string + Integration string + IssueType string + AccountID string + Region string + SSMDocument string + InstallerScript string } // TaskNameForDiscoverEC2 returns a deterministic name for the DiscoverEC2 task type. @@ -233,6 +235,10 @@ func TaskNameForDiscoverEC2(parts TaskNameForDiscoverEC2Parts) string { bs = append(bs, []byte(parts.AccountID)...) bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.Region)))...) bs = append(bs, []byte(parts.Region)...) + bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.SSMDocument)))...) + bs = append(bs, []byte(parts.SSMDocument)...) + bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.InstallerScript)))...) + bs = append(bs, []byte(parts.InstallerScript)...) return uuid.NewSHA1(discoverEC2Namespace, bs).String() } diff --git a/api/types/usertasks/object_test.go b/api/types/usertasks/object_test.go index d5fa6c43744fc..f2298f2132829 100644 --- a/api/types/usertasks/object_test.go +++ b/api/types/usertasks/object_test.go @@ -250,7 +250,7 @@ func TestNewDiscoverEC2UserTask(t *testing.T) { Kind: "user_task", Version: "v1", Metadata: &headerv1.Metadata{ - Name: "154e1429-da26-5ce2-add2-b0e77a27dd96", + Name: "f36b8798-fdec-59fe-8bd0-33f4890ced05", Expires: userTaskExpirationTimestamp, }, Spec: baseEC2DiscoverTaskSpec, diff --git a/lib/srv/discovery/discovery.go b/lib/srv/discovery/discovery.go index adb2c6727de8a..7c5a6808506b7 100644 --- a/lib/srv/discovery/discovery.go +++ b/lib/srv/discovery/discovery.go @@ -981,10 +981,12 @@ func (s *Server) handleEC2RemoteInstallation(instances *server.EC2Instances) err for _, instance := range req.Instances { s.awsEC2Tasks.addFailedEnrollment( awsEC2TaskKey{ - accountID: instances.AccountID, - integration: instances.Integration, - issueType: usertasks.AutoDiscoverEC2IssueSSMInvocationFailure, - region: instances.Region, + accountID: instances.AccountID, + integration: instances.Integration, + issueType: usertasks.AutoDiscoverEC2IssueSSMInvocationFailure, + region: instances.Region, + ssmDocument: req.DocumentName, + installerScript: req.InstallerScriptName(), }, &usertasksv1.DiscoverEC2Instance{ // TODO(marco): add instance name diff --git a/lib/srv/discovery/status.go b/lib/srv/discovery/status.go index 8d6960e557e6d..4bb70efaa5b66 100644 --- a/lib/srv/discovery/status.go +++ b/lib/srv/discovery/status.go @@ -302,10 +302,12 @@ func (s *Server) ReportEC2SSMInstallationResult(ctx context.Context, result *ser s.awsEC2Tasks.addFailedEnrollment( awsEC2TaskKey{ - integration: result.IntegrationName, - issueType: result.IssueType, - accountID: result.SSMRunEvent.AccountID, - region: result.SSMRunEvent.Region, + integration: result.IntegrationName, + issueType: result.IssueType, + accountID: result.SSMRunEvent.AccountID, + region: result.SSMRunEvent.Region, + ssmDocument: result.SSMDocumentName, + installerScript: result.InstallerScript, }, &usertasksv1.DiscoverEC2Instance{ // TODO(marco): add instance name @@ -333,10 +335,12 @@ type awsEC2Tasks struct { // awsEC2TaskKey identifies a UserTask group. type awsEC2TaskKey struct { - integration string - issueType string - accountID string - region string + integration string + issueType string + accountID string + region string + ssmDocument string + installerScript string } // iterationStarted clears out any in memory issues that were recorded. @@ -431,10 +435,12 @@ func (s *Server) acquireSemaphoreForUserTask(userTaskName string) (releaseFn fun // All of this flow is protected by a lock to ensure there's no race between this and other DiscoveryServices. func (s *Server) mergeUpsertDiscoverEC2Task(taskGroup awsEC2TaskKey, failedInstances map[string]*usertasksv1.DiscoverEC2Instance) error { userTaskName := usertasks.TaskNameForDiscoverEC2(usertasks.TaskNameForDiscoverEC2Parts{ - Integration: taskGroup.integration, - IssueType: taskGroup.issueType, - AccountID: taskGroup.accountID, - Region: taskGroup.region, + Integration: taskGroup.integration, + IssueType: taskGroup.issueType, + AccountID: taskGroup.accountID, + Region: taskGroup.region, + SSMDocument: taskGroup.ssmDocument, + InstallerScript: taskGroup.installerScript, }) releaseFn, ctxWithLease, err := s.acquireSemaphoreForUserTask(userTaskName) diff --git a/lib/srv/server/ssm_install.go b/lib/srv/server/ssm_install.go index ac74601e7f3ae..6c0c2f427708e 100644 --- a/lib/srv/server/ssm_install.go +++ b/lib/srv/server/ssm_install.go @@ -63,6 +63,10 @@ type SSMInstallationResult struct { // IssueType identifies the type of issue that occurred if the installation failed. // These are well known identifiers that can be found at types.AutoDiscoverEC2Issue*. IssueType string + // SSMDocumentName is the Amazon SSM Document Name used to install Teleport into the instance. + SSMDocumentName string + // InstallerScript is the Teleport Installer script name used to install Teleport into the instance. + InstallerScript string } // SSMInstaller handles running SSM commands that install Teleport on EC2 instances. @@ -95,6 +99,16 @@ type SSMRunRequest struct { DiscoveryConfig string } +// InstallerScriptName returns the Teleport Installer script name. +// Returns empty string if not defined. +func (r *SSMRunRequest) InstallerScriptName() string { + if r == nil || r.Params == nil { + return "" + } + + return r.Params[ParamScriptName] +} + // CheckAndSetDefaults ensures the emitter is present and creates a default logger if one is not provided. func (c *SSMInstallerConfig) checkAndSetDefaults() error { if c.ReportSSMInstallationResultFunc == nil { @@ -212,6 +226,8 @@ func invalidSSMInstanceInstallationResult(req SSMRunRequest, instanceID, status, IntegrationName: req.IntegrationName, DiscoveryConfig: req.DiscoveryConfig, IssueType: issueType, + SSMDocumentName: req.DocumentName, + InstallerScript: req.InstallerScriptName(), } } @@ -359,6 +375,8 @@ func (si *SSMInstaller) checkCommand(ctx context.Context, req SSMRunRequest, com IntegrationName: req.IntegrationName, DiscoveryConfig: req.DiscoveryConfig, IssueType: usertasks.AutoDiscoverEC2IssueSSMScriptFailure, + SSMDocumentName: req.DocumentName, + InstallerScript: req.InstallerScriptName(), })) } @@ -373,6 +391,8 @@ func (si *SSMInstaller) checkCommand(ctx context.Context, req SSMRunRequest, com IntegrationName: req.IntegrationName, DiscoveryConfig: req.DiscoveryConfig, IssueType: usertasks.AutoDiscoverEC2IssueSSMScriptFailure, + SSMDocumentName: req.DocumentName, + InstallerScript: req.InstallerScriptName(), })) } } diff --git a/lib/srv/server/ssm_install_test.go b/lib/srv/server/ssm_install_test.go index 5d24398433bcc..2107e91b0e590 100644 --- a/lib/srv/server/ssm_install_test.go +++ b/lib/srv/server/ssm_install_test.go @@ -144,7 +144,8 @@ func TestSSMInstaller(t *testing.T) { Status: ssm.CommandStatusSuccess, InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument", }}, }, { @@ -189,7 +190,8 @@ func TestSSMInstaller(t *testing.T) { Status: ssm.CommandStatusSuccess, InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument-without-sshdConfigPath-param", }}, }, { @@ -236,7 +238,8 @@ func TestSSMInstaller(t *testing.T) { StandardError: "timeout error", InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument", }}, }, { @@ -287,7 +290,8 @@ func TestSSMInstaller(t *testing.T) { StandardError: "timeout error", InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument", }}, }, { @@ -355,7 +359,8 @@ func TestSSMInstaller(t *testing.T) { Status: ssm.CommandStatusSuccess, InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument", }, { SSMRunEvent: &events.SSMRun{ @@ -370,7 +375,8 @@ func TestSSMInstaller(t *testing.T) { ExitCode: -1, Status: "SSM Agent in EC2 Instance is not connecting to SSM Service. Restart or reinstall the SSM service. See https://docs.aws.amazon.com/systems-manager/latest/userguide/ami-preinstalled-agent.html#verify-ssm-agent-status for more details.", }, - IssueType: "ec2-ssm-agent-connection-lost", + IssueType: "ec2-ssm-agent-connection-lost", + SSMDocumentName: "ssmdocument", }, { SSMRunEvent: &events.SSMRun{ @@ -385,7 +391,8 @@ func TestSSMInstaller(t *testing.T) { ExitCode: -1, Status: "EC2 instance is running an unsupported Operating System. Only Linux is supported.", }, - IssueType: "ec2-ssm-unsupported-os", + IssueType: "ec2-ssm-unsupported-os", + SSMDocumentName: "ssmdocument", }, { SSMRunEvent: &events.SSMRun{ @@ -400,7 +407,8 @@ func TestSSMInstaller(t *testing.T) { ExitCode: -1, Status: "EC2 Instance is not registered in SSM. Make sure that the instance has AmazonSSMManagedInstanceCore policy assigned.", }, - IssueType: "ec2-ssm-agent-not-registered", + IssueType: "ec2-ssm-agent-not-registered", + SSMDocumentName: "ssmdocument", }, }, }, @@ -456,7 +464,8 @@ func TestSSMInstaller(t *testing.T) { StandardOutput: "custom output", InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument", }}, }, { @@ -497,7 +506,8 @@ func TestSSMInstaller(t *testing.T) { Status: ssm.CommandStatusSuccess, InvocationURL: "https://eu-central-1.console.aws.amazon.com/systems-manager/run-command/command-id-1/instance-id-1", }, - IssueType: "ec2-ssm-script-failure", + IssueType: "ec2-ssm-script-failure", + SSMDocumentName: "ssmdocument", }}, }, // todo(amk): test that incomplete commands eventually return