mirror of https://github.com/docker/compose.git
use an initContainer to inject secrets as /run/secrets/xx
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
b05af0c0ac
commit
85b3cbd6ea
|
@ -7,6 +7,8 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/ecs-plugin/pkg/amazon/cloudformation"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
amazon "github.com/docker/ecs-plugin/pkg/amazon/backend"
|
||||
|
@ -59,11 +61,11 @@ func ConvertCommand(dockerCli command.Cli, options *composeOptions) *cobra.Comma
|
|||
return err
|
||||
}
|
||||
|
||||
j, err := template.JSON()
|
||||
json, err := cloudformation.Marshall(template)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to generate JSON: %s\n", err)
|
||||
} else {
|
||||
fmt.Printf("%s\n", string(j))
|
||||
fmt.Printf("%s\n", string(json))
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
|
|
14
ecs/go.sum
14
ecs/go.sum
|
@ -19,12 +19,8 @@ github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkK
|
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aws/aws-sdk-go v1.30.22 h1:wImJ8jQrplgmxaTeUY7FrJFn4te/VtWq+mmmJ1TnWAg=
|
||||
github.com/aws/aws-sdk-go v1.30.22/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.33.18 h1:Ccy1SV2SsgJU3rfrD+SOhQ0jvuzfrFuja/oKI86ruPw=
|
||||
github.com/aws/aws-sdk-go v1.33.18/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/awslabs/goformation/v4 v4.8.0 h1:UiUhyokRy3suEqBXTnipvY8klqY3Eyl4GCH17brraEc=
|
||||
github.com/awslabs/goformation/v4 v4.8.0/go.mod h1:GcJULxCJfloT+3pbqCluXftdEK2AD/UqpS3hkaaBntg=
|
||||
github.com/awslabs/goformation/v4 v4.14.0 h1:E2Pet9eIqA4qzt3dzzzE4YN83V4Kyfbcio0VokBC9TA=
|
||||
github.com/awslabs/goformation/v4 v4.14.0/go.mod h1:GcJULxCJfloT+3pbqCluXftdEK2AD/UqpS3hkaaBntg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
@ -58,14 +54,6 @@ github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiK
|
|||
github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo=
|
||||
github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
|
||||
github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200624120600-614475470cd8 h1:sVvKsoXizFOuJNc8dM91IeET2/zDNFj3hwHgk437iJ8=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200624120600-614475470cd8/go.mod h1:ih9anT8po+49hrb+1j3ldIJ/YRAaBH52ErlQLTKE2Yo=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200707124823-710ff8e60ad9 h1:WkFqc6UpRqxROso9KC+ceaTiXx/VWpeO1x+NV0d4d+o=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200707124823-710ff8e60ad9/go.mod h1:ArodJ6gsEB7iWKrbV3fSHZ08LlBvSVB0Oqg04fX86t4=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200709084333-492a50989a5a h1:pIiSz5jML7rQ1aupg/KHlTqCxhyXvIgeDMf4kDTzIg8=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200709084333-492a50989a5a/go.mod h1:ArodJ6gsEB7iWKrbV3fSHZ08LlBvSVB0Oqg04fX86t4=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200710075715-6fcc35384ee1 h1:F+YIkKDMHdgZBacawhFY1P9RAIgO+6uv2te6hjsjzF0=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200710075715-6fcc35384ee1/go.mod h1:ArodJ6gsEB7iWKrbV3fSHZ08LlBvSVB0Oqg04fX86t4=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200716130117-e87e4f7839e3 h1:+ntlMTrEcScJjlnEOP8P1IIrusJaR93Eazr66YgUueA=
|
||||
github.com/compose-spec/compose-go v0.0.0-20200716130117-e87e4f7839e3/go.mod h1:ArodJ6gsEB7iWKrbV3fSHZ08LlBvSVB0Oqg04fX86t4=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
|
@ -80,6 +68,7 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv
|
|||
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
|
||||
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
|
@ -475,6 +464,7 @@ gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
|
|||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8=
|
||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787 h1:O69FD9pJA4WUZlEwYatBEEkRWKQ5cKodWpdKTrCS/iQ=
|
||||
vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
|
||||
|
|
|
@ -2,9 +2,12 @@ package backend
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/awslabs/goformation/v4/cloudformation/secretsmanager"
|
||||
|
||||
ecsapi "github.com/aws/aws-sdk-go/service/ecs"
|
||||
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||
cloudmapapi "github.com/aws/aws-sdk-go/service/servicediscovery"
|
||||
|
@ -93,6 +96,30 @@ func (b Backend) Convert(project *types.Project) (*cloudformation.Template, erro
|
|||
networks[net.Name] = convertNetwork(project, net, cloudformation.Ref(ParameterVPCId), template)
|
||||
}
|
||||
|
||||
for i, s := range project.Secrets {
|
||||
if s.External.External {
|
||||
continue
|
||||
}
|
||||
secret, err := ioutil.ReadFile(s.File)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%sSecret", normalizeResourceName(s.Name))
|
||||
template.Resources[name] = &secretsmanager.Secret{
|
||||
Description: "",
|
||||
SecretString: string(secret),
|
||||
Tags: []tags.Tag{
|
||||
{
|
||||
Key: compose.ProjectTag,
|
||||
Value: project.Name,
|
||||
},
|
||||
},
|
||||
}
|
||||
s.Name = cloudformation.Ref(name)
|
||||
project.Secrets[i] = s
|
||||
}
|
||||
|
||||
logGroup := fmt.Sprintf("/docker-compose/%s", project.Name)
|
||||
template.Resources["LogGroup"] = &logs.LogGroup{
|
||||
LogGroupName: logGroup,
|
||||
|
|
|
@ -37,8 +37,14 @@ var compatibleComposeAttributes = []string{
|
|||
"services.ports.mode",
|
||||
"services.ports.target",
|
||||
"services.ports.protocol",
|
||||
"services.secrets",
|
||||
"services.secrets.source",
|
||||
"services.secrets.target",
|
||||
"services.user",
|
||||
"services.working_dir",
|
||||
"secrets.external",
|
||||
"secrets.name",
|
||||
"secrets.file",
|
||||
}
|
||||
|
||||
func (c *FargateCompatibilityChecker) CheckImage(service *types.ServiceConfig) {
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
"github.com/docker/ecs-plugin/pkg/compose"
|
||||
)
|
||||
|
||||
const secretsInitContainerImage = "docker/ecs-secrets-sidecar"
|
||||
|
||||
func Convert(project *types.Project, service types.ServiceConfig) (*ecs.TaskDefinition, error) {
|
||||
cpu, mem, err := toLimits(service)
|
||||
if err != nil {
|
||||
|
@ -37,50 +39,118 @@ func Convert(project *types.Project, service types.ServiceConfig) (*ecs.TaskDefi
|
|||
fmt.Sprintf(" %s.local", project.Name),
|
||||
}))
|
||||
|
||||
return &ecs.TaskDefinition{
|
||||
ContainerDefinitions: []ecs.TaskDefinition_ContainerDefinition{
|
||||
{
|
||||
Command: service.Command,
|
||||
DisableNetworking: service.NetworkMode == "none",
|
||||
DnsSearchDomains: service.DNSSearch,
|
||||
DnsServers: service.DNS,
|
||||
DockerSecurityOptions: service.SecurityOpt,
|
||||
EntryPoint: service.Entrypoint,
|
||||
Environment: toKeyValuePair(service.Environment),
|
||||
Essential: true,
|
||||
ExtraHosts: toHostEntryPtr(service.ExtraHosts),
|
||||
FirelensConfiguration: nil,
|
||||
HealthCheck: toHealthCheck(service.HealthCheck),
|
||||
Hostname: service.Hostname,
|
||||
Image: service.Image,
|
||||
Interactive: false,
|
||||
Links: nil,
|
||||
LinuxParameters: toLinuxParameters(service),
|
||||
LogConfiguration: &ecs.TaskDefinition_LogConfiguration{
|
||||
LogDriver: ecsapi.LogDriverAwslogs,
|
||||
Options: map[string]string{
|
||||
"awslogs-region": cloudformation.Ref("AWS::Region"),
|
||||
"awslogs-group": cloudformation.Ref("LogGroup"),
|
||||
"awslogs-stream-prefix": project.Name,
|
||||
},
|
||||
},
|
||||
MemoryReservation: memReservation,
|
||||
Name: service.Name,
|
||||
PortMappings: toPortMappings(service.Ports),
|
||||
Privileged: service.Privileged,
|
||||
PseudoTerminal: service.Tty,
|
||||
ReadonlyRootFilesystem: service.ReadOnly,
|
||||
RepositoryCredentials: credential,
|
||||
ResourceRequirements: nil,
|
||||
StartTimeout: 0,
|
||||
StopTimeout: durationToInt(service.StopGracePeriod),
|
||||
SystemControls: toSystemControls(service.Sysctls),
|
||||
Ulimits: toUlimits(service.Ulimits),
|
||||
User: service.User,
|
||||
VolumesFrom: nil,
|
||||
WorkingDirectory: service.WorkingDir,
|
||||
},
|
||||
logConfiguration := &ecs.TaskDefinition_LogConfiguration{
|
||||
LogDriver: ecsapi.LogDriverAwslogs,
|
||||
Options: map[string]string{
|
||||
"awslogs-region": cloudformation.Ref("AWS::Region"),
|
||||
"awslogs-group": cloudformation.Ref("LogGroup"),
|
||||
"awslogs-stream-prefix": project.Name,
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
containers []ecs.TaskDefinition_ContainerDefinition
|
||||
volumes []ecs.TaskDefinition_Volume
|
||||
mounts []ecs.TaskDefinition_MountPoint
|
||||
initContainers []ecs.TaskDefinition_ContainerDependency
|
||||
)
|
||||
if len(service.Secrets) > 0 {
|
||||
volumes = append(volumes, ecs.TaskDefinition_Volume{
|
||||
Name: "secrets",
|
||||
})
|
||||
mounts = append(mounts, ecs.TaskDefinition_MountPoint{
|
||||
ContainerPath: "/run/secrets/",
|
||||
ReadOnly: true,
|
||||
SourceVolume: "secrets",
|
||||
})
|
||||
initContainers = append(initContainers, ecs.TaskDefinition_ContainerDependency{
|
||||
Condition: ecsapi.ContainerConditionSuccess,
|
||||
ContainerName: "Secrets_InitContainer",
|
||||
})
|
||||
|
||||
var (
|
||||
names []string
|
||||
secrets []ecs.TaskDefinition_Secret
|
||||
)
|
||||
for _, s := range service.Secrets {
|
||||
secretConfig := project.Secrets[s.Source]
|
||||
if s.Target == "" {
|
||||
s.Target = s.Source
|
||||
}
|
||||
secrets = append(secrets, ecs.TaskDefinition_Secret{
|
||||
Name: s.Target,
|
||||
ValueFrom: secretConfig.Name,
|
||||
})
|
||||
name := s.Target
|
||||
if ext, ok := secretConfig.Extensions[compose.ExtensionKeys]; ok {
|
||||
var keys []string
|
||||
if key, ok := ext.(string); ok {
|
||||
keys = append(keys, key)
|
||||
} else {
|
||||
for _, k := range ext.([]interface{}) {
|
||||
keys = append(keys, k.(string))
|
||||
}
|
||||
}
|
||||
name = fmt.Sprintf("%s:%s", s.Target, strings.Join(keys, ","))
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
containers = append(containers, ecs.TaskDefinition_ContainerDefinition{
|
||||
Name: fmt.Sprintf("%s_Secrets_InitContainer", normalizeResourceName(service.Name)),
|
||||
Image: secretsInitContainerImage,
|
||||
Command: names,
|
||||
Essential: false, // FIXME this will be ignored, see https://github.com/awslabs/goformation/issues/61#issuecomment-625139607
|
||||
LogConfiguration: logConfiguration,
|
||||
MountPoints: []ecs.TaskDefinition_MountPoint{
|
||||
{
|
||||
ContainerPath: "/run/secrets/",
|
||||
ReadOnly: false,
|
||||
SourceVolume: "secrets",
|
||||
},
|
||||
},
|
||||
Secrets: secrets,
|
||||
})
|
||||
}
|
||||
|
||||
containers = append(containers, ecs.TaskDefinition_ContainerDefinition{
|
||||
Command: service.Command,
|
||||
DisableNetworking: service.NetworkMode == "none",
|
||||
DependsOnProp: initContainers,
|
||||
DnsSearchDomains: service.DNSSearch,
|
||||
DnsServers: service.DNS,
|
||||
DockerSecurityOptions: service.SecurityOpt,
|
||||
EntryPoint: service.Entrypoint,
|
||||
Environment: toKeyValuePair(service.Environment),
|
||||
Essential: true,
|
||||
ExtraHosts: toHostEntryPtr(service.ExtraHosts),
|
||||
FirelensConfiguration: nil,
|
||||
HealthCheck: toHealthCheck(service.HealthCheck),
|
||||
Hostname: service.Hostname,
|
||||
Image: service.Image,
|
||||
Interactive: false,
|
||||
Links: nil,
|
||||
LinuxParameters: toLinuxParameters(service),
|
||||
LogConfiguration: logConfiguration,
|
||||
MemoryReservation: memReservation,
|
||||
MountPoints: mounts,
|
||||
Name: service.Name,
|
||||
PortMappings: toPortMappings(service.Ports),
|
||||
Privileged: service.Privileged,
|
||||
PseudoTerminal: service.Tty,
|
||||
ReadonlyRootFilesystem: service.ReadOnly,
|
||||
RepositoryCredentials: credential,
|
||||
ResourceRequirements: nil,
|
||||
StartTimeout: 0,
|
||||
StopTimeout: durationToInt(service.StopGracePeriod),
|
||||
SystemControls: toSystemControls(service.Sysctls),
|
||||
Ulimits: toUlimits(service.Ulimits),
|
||||
User: service.User,
|
||||
VolumesFrom: nil,
|
||||
WorkingDirectory: service.WorkingDir,
|
||||
})
|
||||
|
||||
return &ecs.TaskDefinition{
|
||||
ContainerDefinitions: containers,
|
||||
Cpu: cpu,
|
||||
Family: fmt.Sprintf("%s-%s", project.Name, service.Name),
|
||||
IpcMode: service.Ipc,
|
||||
|
@ -90,6 +160,7 @@ func Convert(project *types.Project, service types.ServiceConfig) (*ecs.TaskDefi
|
|||
PlacementConstraints: toPlacementConstraints(service.Deploy),
|
||||
ProxyConfiguration: nil,
|
||||
RequiresCompatibilities: []string{ecsapi.LaunchTypeFargate},
|
||||
Volumes: volumes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package cloudformation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/awslabs/goformation/v4/cloudformation"
|
||||
)
|
||||
|
||||
func Marshall(template *cloudformation.Template) ([]byte, error) {
|
||||
raw, err := template.JSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var unmarshalled interface{}
|
||||
if err := json.Unmarshal(raw, &unmarshalled); err != nil {
|
||||
return nil, fmt.Errorf("invalid JSON: %s", err)
|
||||
}
|
||||
|
||||
if input, ok := unmarshalled.(map[string]interface{}); ok {
|
||||
if resources, ok := input["Resources"]; ok {
|
||||
for _, uresource := range resources.(map[string]interface{}) {
|
||||
if resource, ok := uresource.(map[string]interface{}); ok {
|
||||
if resource["Type"] == "AWS::ECS::TaskDefinition" {
|
||||
properties := resource["Properties"].(map[string]interface{})
|
||||
for _, def := range properties["ContainerDefinitions"].([]interface{}) {
|
||||
containerDefinition := def.(map[string]interface{})
|
||||
if strings.HasSuffix(containerDefinition["Name"].(string), "_InitContainer") {
|
||||
containerDefinition["Essential"] = "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raw, err = json.MarshalIndent(unmarshalled, "", " ")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid JSON: %s", err)
|
||||
}
|
||||
return raw, err
|
||||
}
|
|
@ -6,6 +6,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
cloudformation2 "github.com/docker/ecs-plugin/pkg/amazon/cloudformation"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
|
@ -164,7 +166,7 @@ func (s sdk) StackExists(ctx context.Context, name string) (bool, error) {
|
|||
|
||||
func (s sdk) CreateStack(ctx context.Context, name string, template *cf.Template, parameters map[string]string) error {
|
||||
logrus.Debug("Create CloudFormation stack")
|
||||
json, err := template.JSON()
|
||||
json, err := cloudformation2.Marshall(template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -192,7 +194,7 @@ func (s sdk) CreateStack(ctx context.Context, name string, template *cf.Template
|
|||
|
||||
func (s sdk) CreateChangeSet(ctx context.Context, name string, template *cf.Template, parameters map[string]string) (string, error) {
|
||||
logrus.Debug("Create CloudFormation Changeset")
|
||||
json, err := template.JSON()
|
||||
json, err := cloudformation2.Marshall(template)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -6,4 +6,5 @@ const (
|
|||
ExtensionPullCredentials = "x-aws-pull_credentials"
|
||||
ExtensionLB = "x-aws-loadbalancer"
|
||||
ExtensionCluster = "x-aws-cluster"
|
||||
ExtensionKeys = "x-aws-keys"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
FROM golang:1.14.4-alpine AS builder
|
||||
WORKDIR $GOPATH/src/github.com/docker/ecs-secrets
|
||||
COPY . .
|
||||
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/secrets
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /go/bin/secrets /secrets
|
||||
ENTRYPOINT ["/secrets"]
|
|
@ -0,0 +1,85 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// return codes:
|
||||
// 1: failed to read secret from env
|
||||
// 2: failed to parse hierarchical secret
|
||||
// 3: failed to write secret content into file
|
||||
func main() {
|
||||
for _, name := range os.Args[1:] {
|
||||
i := strings.Index(name, ":")
|
||||
var keys []string
|
||||
if i > 0 {
|
||||
keys = strings.Split(name[i+1:], ",")
|
||||
name = name[:i]
|
||||
}
|
||||
value, ok := os.LookupEnv(name)
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "%q variable not set", name)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
secrets := filepath.Join("/run/secrets", name)
|
||||
|
||||
if len(keys) == 0 {
|
||||
// raw secret
|
||||
fmt.Printf("inject secret %q info %s\n", name, secrets)
|
||||
err := ioutil.WriteFile(secrets, []byte(value), 0444)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(3)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
var unmarshalled interface{}
|
||||
err := json.Unmarshal([]byte(value), &unmarshalled)
|
||||
if err == nil {
|
||||
if dict, ok := unmarshalled.(map[string]interface{}); ok {
|
||||
os.MkdirAll(secrets, 0555)
|
||||
for k, v := range dict {
|
||||
if !contains(keys, k) && !contains(keys, "*") {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(secrets, k)
|
||||
fmt.Printf("inject secret %q info %s\n", k, path)
|
||||
|
||||
var raw []byte
|
||||
if s, ok := v.(string); ok {
|
||||
raw = []byte(s)
|
||||
} else {
|
||||
raw, err = json.Marshal(v)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(path, raw, 0444)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func contains(keys []string, s string) bool {
|
||||
for _, k := range keys {
|
||||
if k == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Loading…
Reference in New Issue