Skip to content

Commit

Permalink
feat(cli): display secrets as subcategory in svc_show (aws#1704)
Browse files Browse the repository at this point in the history
This change displays secrets as a separate category (not within "Variables") in `svc show`. If the secret value comes from Parameter Store, it is preceded by `parameter/`. Otherwise, if it comes from Secrets Manager, it is displayed as an ARN.

Addresses aws#720

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
  • Loading branch information
huanjani authored Nov 24, 2020
1 parent 42567bf commit 6128e9c
Show file tree
Hide file tree
Showing 10 changed files with 671 additions and 107 deletions.
43 changes: 39 additions & 4 deletions internal/pkg/aws/ecs/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,50 @@ func (t TaskStatus) HumanString() string {
// TaskDefinition wraps up ECS TaskDefinition struct.
type TaskDefinition ecs.TaskDefinition

// ContainerEnvVar holds basic info of an environment variable.
type ContainerEnvVar struct {
Name string
Container string
Value string
}

// EnvironmentVariables returns environment variables of the task definition.
func (t *TaskDefinition) EnvironmentVariables() map[string]string {
envs := make(map[string]string)
for _, env := range t.ContainerDefinitions[0].Environment {
envs[aws.StringValue(env.Name)] = aws.StringValue(env.Value)
func (t *TaskDefinition) EnvironmentVariables() []*ContainerEnvVar {
var envs []*ContainerEnvVar
for _, container := range t.ContainerDefinitions {
for _, env := range container.Environment {
envs = append(envs, &ContainerEnvVar{
aws.StringValue(env.Name),
aws.StringValue(container.Name),
aws.StringValue(env.Value),
})
}
}
return envs
}

// ContainerSecret holds basic info of a secret.
type ContainerSecret struct {
Name string
Container string
ValueFrom string
}

// Secrets returns secrets of the task definition.
func (t *TaskDefinition) Secrets() []*ContainerSecret {
var secrets []*ContainerSecret
for _, container := range t.ContainerDefinitions {
for _, secret := range container.Secrets {
secrets = append(secrets, &ContainerSecret{
aws.StringValue(secret.Name),
aws.StringValue(container.Name),
aws.StringValue(secret.ValueFrom),
})
}
}
return secrets
}

// TaskID parses the task ARN and returns the task ID.
// For example: arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d,
// arn:aws:ecs:us-west-2:123456789:task/4082490ee6c245e09d2145010aa1ba8d
Expand Down
75 changes: 70 additions & 5 deletions internal/pkg/aws/ecs/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ func TestTaskDefinition_EnvVars(t *testing.T) {
testCases := map[string]struct {
inContainers []*ecs.ContainerDefinition

wantEnvVars map[string]string
wantEnvVars []*ContainerEnvVar
}{
"should return wrapped error given error": {
"should return wrapped error given error; otherwise should return list of ContainerEnvVar objects": {
inContainers: []*ecs.ContainerDefinition{
{
Environment: []*ecs.KeyValuePair{
Expand All @@ -258,12 +258,21 @@ func TestTaskDefinition_EnvVars(t *testing.T) {
Value: aws.String("prod"),
},
},
Name: aws.String("container"),
},
},

wantEnvVars: map[string]string{
"COPILOT_SERVICE_NAME": "my-svc",
"COPILOT_ENVIRONMENT_NAME": "prod",
wantEnvVars: []*ContainerEnvVar{
{
Name: "COPILOT_SERVICE_NAME",
Container: "container",
Value: "my-svc",
},
{
Name: "COPILOT_ENVIRONMENT_NAME",
Container: "container",
Value: "prod",
},
},
},
}
Expand All @@ -285,3 +294,59 @@ func TestTaskDefinition_EnvVars(t *testing.T) {

}
}

func TestTaskDefinition_Secrets(t *testing.T) {
testCases := map[string]struct {
inContainers []*ecs.ContainerDefinition

wantedSecrets []*ContainerSecret
}{
"should return secrets of the task definition as a list of ContainerSecret objects": {
inContainers: []*ecs.ContainerDefinition{
{
Name: aws.String("container"),
Secrets: []*ecs.Secret{
{
Name: aws.String("GITHUB_WEBHOOK_SECRET"),
ValueFrom: aws.String("GH_WEBHOOK_SECRET"),
},
{
Name: aws.String("SOME_OTHER_SECRET"),
ValueFrom: aws.String("SHHHHHHHH"),
},
},
},
},

wantedSecrets: []*ContainerSecret{
{
Name: "GITHUB_WEBHOOK_SECRET",
Container: "container",
ValueFrom: "GH_WEBHOOK_SECRET",
},
{
Name: "SOME_OTHER_SECRET",
Container: "container",
ValueFrom: "SHHHHHHHH",
},
},
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
// GIVEN
ctrl := gomock.NewController(t)
defer ctrl.Finish()

taskDefinition := TaskDefinition{
ContainerDefinitions: tc.inContainers,
}

gotSecrets := taskDefinition.Secrets()

require.Equal(t, tc.wantedSecrets, gotSecrets)
})

}
}
18 changes: 14 additions & 4 deletions internal/pkg/describe/backend_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"sort"
"text/tabwriter"

"github.com/aws/copilot-cli/internal/pkg/deploy/cloudformation/stack"
Expand Down Expand Up @@ -99,7 +98,8 @@ func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) {

var configs []*ServiceConfig
var services []*ServiceDiscovery
var envVars []*EnvVars
var envVars []*envVar
var secrets []*secret
for _, env := range environments {
err := d.initServiceDescriber(env)
if err != nil {
Expand Down Expand Up @@ -130,9 +130,12 @@ func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) {
return nil, fmt.Errorf("retrieve environment variables: %w", err)
}
envVars = append(envVars, flattenEnvVars(env, backendSvcEnvVars)...)
webSvcSecrets, err := d.svcDescriber[env].Secrets()
if err != nil {
return nil, fmt.Errorf("retrieve secrets: %w", err)
}
secrets = append(secrets, flattenSecrets(env, webSvcSecrets)...)
}
sort.SliceStable(envVars, func(i, j int) bool { return envVars[i].Environment < envVars[j].Environment })
sort.SliceStable(envVars, func(i, j int) bool { return envVars[i].Name < envVars[j].Name })

resources := make(map[string][]*CfnResource)
if d.enableResources {
Expand All @@ -156,6 +159,7 @@ func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) {
Configurations: configs,
ServiceDiscovery: services,
Variables: envVars,
Secrets: secrets,
Resources: resources,
}, nil
}
Expand All @@ -168,6 +172,7 @@ type backendSvcDesc struct {
Configurations configurations `json:"configurations"`
ServiceDiscovery serviceDiscoveries `json:"serviceDiscovery"`
Variables envVars `json:"variables"`
Secrets secrets `json:"secrets,omitempty"`
Resources cfnResources `json:"resources,omitempty"`
}

Expand Down Expand Up @@ -198,6 +203,11 @@ func (w *backendSvcDesc) HumanString() string {
fmt.Fprint(writer, color.Bold.Sprint("\nVariables\n\n"))
writer.Flush()
w.Variables.humanString(writer)
if len(w.Secrets) != 0 {
fmt.Fprint(writer, color.Bold.Sprint("\nSecrets\n\n"))
writer.Flush()
w.Secrets.humanString(writer)
}
if len(w.Resources) != 0 {
fmt.Fprint(writer, color.Bold.Sprint("\nResources\n"))
writer.Flush()
Expand Down
Loading

0 comments on commit 6128e9c

Please sign in to comment.