Skip to content

Commit 31f52b1

Browse files
Preliminary support for @DOCKEROPTS
@DOCKEROPTS is imagined to make it easier to lift summon secrets into docker. With usage like this in mind: summon docker run @DOCKEROPTS -it alpine
1 parent 6145b9f commit 31f52b1

File tree

8 files changed

+140
-8
lines changed

8 files changed

+140
-8
lines changed

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ COPY go.mod go.sum ./
99

1010
RUN apk add --no-cache bash \
1111
build-base \
12+
docker-cli \
1213
git && \
1314
go mod download && \
1415
go get -u github.com/jstemmer/go-junit-report && \

Dockerfile.acceptance

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ RUN apk add --no-cache bash \
55
git \
66
libffi-dev \
77
ruby-bundler \
8-
ruby-dev
8+
ruby-dev \
9+
docker-cli
910

1011
# Install summon prerequisites
1112
WORKDIR /summon
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Feature: dockeropts
2+
3+
As a developer using summon
4+
I want to be able to use my secrets in a docker container environment
5+
I do not want to add the summon binary to every container
6+
7+
Scenario: Running an dockeropts-consuming command
8+
Given a file named "secrets.yml" with:
9+
"""
10+
DB_PASSWORD: !var very/secret/db-password
11+
"""
12+
13+
And a secret "very/secret/db-password" with "notSoSecret"
14+
When I successfully run `summon -p ./provider docker run --rm @DOCKEROPTS alpine printenv DB_PASSWORD`
15+
Then the output should contain exactly "DB_PASSWORD=notSoSecret\n"

internal/command/action.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package command
33
import (
44
"bytes"
55
"fmt"
6+
"io"
67
"os"
78
"os/exec"
89
"path/filepath"
@@ -11,13 +12,17 @@ import (
1112
"syscall"
1213

1314
"github.com/codegangsta/cli"
15+
1416
prov "github.com/cyberark/summon/provider"
1517
"github.com/cyberark/summon/secretsyml"
1618
)
1719

1820
// ActionConfig is an object that holds all the info needed to run
1921
// a Summon instance
2022
type ActionConfig struct {
23+
StdIn io.Reader
24+
StdOut io.Writer
25+
StdErr io.Writer
2126
Args []string
2227
Provider string
2328
Filepath string
@@ -31,6 +36,7 @@ type ActionConfig struct {
3136
}
3237

3338
const ENV_FILE_MAGIC = "@SUMMONENVFILE"
39+
const DOCKER_OPTS_MAGIC = "@DOCKEROPTS"
3440
const SUMMON_ENV_KEY_NAME = "SUMMON_ENV"
3541

3642
// Action is the runner for the main program logic
@@ -121,6 +127,9 @@ func runAction(ac *ActionConfig) error {
121127
results := make(chan Result, len(secrets))
122128
var wg sync.WaitGroup
123129

130+
var dockerOpts []string
131+
var dockerOptsMutex sync.Mutex
132+
124133
for key, spec := range secrets {
125134
wg.Add(1)
126135
go func(key string, spec secretsyml.SecretSpec) {
@@ -143,6 +152,16 @@ func runAction(ac *ActionConfig) error {
143152
}
144153

145154
envvar := formatForEnv(key, value, spec, &tempFactory)
155+
156+
// Generate Docker options
157+
dockerOptsMutex.Lock()
158+
defer dockerOptsMutex.Unlock()
159+
if spec.IsFile() {
160+
fileValue := strings.SplitN(envvar, "=", 2)[1]
161+
dockerOpts = append(dockerOpts, "-v", fileValue+":"+fileValue)
162+
}
163+
dockerOpts = append(dockerOpts, "-e", key)
164+
146165
results <- Result{envvar, nil}
147166
wg.Done()
148167
}(key, spec)
@@ -173,9 +192,38 @@ EnvLoop:
173192
env = append(env, fmt.Sprintf("%s=%s", SUMMON_ENV_KEY_NAME, ac.Environment))
174193
}
175194

195+
// Setup Docker options
196+
var argsWithDockerOpts []string
197+
for _, arg := range ac.Args {
198+
//idx := strings.Index(arg, DOCKER_OPTS_MAGIC)
199+
if arg == DOCKER_OPTS_MAGIC {
200+
// Replace argument with slice of docker options
201+
argsWithDockerOpts = append(argsWithDockerOpts, dockerOpts...)
202+
continue
203+
}
204+
205+
//if idx >= 0 {
206+
// // Replace argument with slice of docker options
207+
// argsWithDockerOpts = append(
208+
// argsWithDockerOpts,
209+
// strings.Replace(arg, DOCKER_OPTS_MAGIC, strings.Join(dockerOpts, " "), -1),
210+
// )
211+
// continue
212+
//}
213+
214+
argsWithDockerOpts = append(argsWithDockerOpts, arg)
215+
}
216+
ac.Args = argsWithDockerOpts
217+
176218
setupEnvFile(ac.Args, env, &tempFactory)
177219

178-
return runSubcommand(ac.Args, append(os.Environ(), env...))
220+
return runSubcommand(
221+
ac.Args,
222+
append(os.Environ(), env...),
223+
ac.StdIn,
224+
ac.StdOut,
225+
ac.StdErr,
226+
)
179227
}
180228

181229
// formatForEnv returns a string in %k=%v format, where %k=namespace of the secret and
@@ -230,7 +278,7 @@ func findInParentTree(secretsFile string, leafDir string) (string, error) {
230278
}
231279
}
232280

233-
// scans arguments for the magic string; if found,
281+
// scans arguments for the envfile magic string; if found,
234282
// creates a tempfile to which all the environment mappings are dumped
235283
// and replaces the magic string with its path.
236284
// Returns the path if so, returns an empty string otherwise.

internal/command/action_test.go

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package command
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67
"io/ioutil"
@@ -12,9 +13,10 @@ import (
1213
"testing"
1314
"time"
1415

15-
"github.com/cyberark/summon/secretsyml"
1616
. "github.com/smartystreets/goconvey/convey"
1717
_ "golang.org/x/net/context"
18+
19+
"github.com/cyberark/summon/secretsyml"
1820
)
1921

2022
func TestConvertSubsToMap(t *testing.T) {
@@ -123,6 +125,51 @@ func TestRunAction(t *testing.T) {
123125

124126
So(string(content), ShouldEqual, expectedValue)
125127
})
128+
129+
Convey("Docker options correctly injected", t, func() {
130+
var buff bytes.Buffer
131+
err := runAction(&ActionConfig{
132+
Provider: "/bin/echo",
133+
StdOut: &buff,
134+
Args: []string{
135+
"docker", "run", "--rm", "@DOCKEROPTS", "alpine", "sh", "-c",
136+
`
137+
echo "$(printenv A)
138+
$(printenv B)
139+
$(cat "$(printenv C)")
140+
$(cat "$(printenv D)")";
141+
`,
142+
},
143+
YamlInline: `
144+
A: |
145+
A's multiple line
146+
value
147+
B: !var B_value
148+
C: !file C_value
149+
D: !var:file D_value
150+
`,
151+
})
152+
153+
code, err := returnStatusOfError(err)
154+
So(err, ShouldBeNil)
155+
So(code, ShouldEqual, 0)
156+
157+
if err != nil || code != 0 {
158+
return
159+
}
160+
161+
So(err, ShouldBeNil)
162+
if err != nil {
163+
return
164+
}
165+
166+
So(string(buff.String()), ShouldEqual, `A's multiple line
167+
value
168+
B_value
169+
C_value
170+
D_value
171+
`)
172+
})
126173
}
127174

128175
func TestDefaultVariableResolution(t *testing.T) {

internal/command/subcommand.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package command
22

33
import (
4+
"io"
45
"os"
56
"os/exec"
67
"os/signal"
@@ -11,16 +12,33 @@ import (
1112
// of an environment populated with secret values. Since we have to
1213
// clean up our temp directories, we remain resident and shuffle
1314
// signals around to the chld and back
14-
func runSubcommand(command []string, env []string) error {
15+
func runSubcommand(
16+
command []string,
17+
env []string,
18+
Stdin io.Reader,
19+
Stdout io.Writer,
20+
Stderr io.Writer,
21+
) error {
1522
binary, lookupErr := exec.LookPath(command[0])
1623
if lookupErr != nil {
1724
return lookupErr
1825
}
1926

2027
runner := exec.Command(binary, command[1:]...)
21-
runner.Stdin = os.Stdin
22-
runner.Stdout = os.Stdout
23-
runner.Stderr = os.Stderr
28+
29+
if Stdin == nil {
30+
Stdin = os.Stdin
31+
}
32+
if Stdout == nil {
33+
Stdout = os.Stdout
34+
}
35+
if Stderr == nil {
36+
Stderr = os.Stderr
37+
}
38+
39+
runner.Stdin = Stdin
40+
runner.Stdout = Stdout
41+
runner.Stderr = Stderr
2442
runner.Env = env
2543

2644
signalChannel := make(chan os.Signal, 1)

test_acceptance

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ docker build --pull -t summon-acceptance -f Dockerfile.acceptance .
99

1010
docker run --rm -t \
1111
-v "$OUTPUT_DIR:/summon/acceptance/output" \
12+
-v "/var/run/docker.sock:/var/run/docker.sock" \
1213
summon-acceptance bash -c 'cucumber --format junit --out ./output'
1314

1415
echo "Results are in $OUTPUT_DIR"

test_unit

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ rm -f "output/*.xml"
99

1010
docker run --rm -t \
1111
-v "$PWD/output:/summon/output" \
12+
-v "/var/run/docker.sock:/var/run/docker.sock" \
1213
summon-builder bash -c "$TEST_CMD;
1314
gocov convert output/c.out | gocov-xml > output/coverage.xml;
1415
"

0 commit comments

Comments
 (0)