Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit c8d3cb0

Browse files
author
Jean-Christophe Sirot
committed
Add support for secrets in composefiles
Signed-off-by: Jean-Christophe Sirot <[email protected]>
1 parent 0942d5c commit c8d3cb0

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

internal/names.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ const (
4545
CredentialRegistryName = Namespace + "registry-creds"
4646
// CredentialRegistryPath is the name to the credential containing registry credentials
4747
CredentialRegistryPath = "/cnab/app/registry-creds.json"
48+
// SecretsPath is the directory where secret files are mounted
49+
SecretsPath = "/cnab/app/secrets"
50+
// SecretsParameterPrefix is the prefix used by WriteOnly parameters
51+
SecretsParameterPrefix = Namespace + "secret."
4852

4953
// ParameterOrchestratorName is the name of the parameter containing the orchestrator
5054
ParameterOrchestratorName = Namespace + "orchestrator"

internal/packager/cnab.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ func ToCNAB(app *types.App, invocationImageName string) (*bundle.Bundle, error)
108108
Definition: name,
109109
}
110110
}
111+
for name, secret := range app.Secrets() {
112+
writeOnly := new(bool)
113+
*writeOnly = true
114+
definitions[internal.SecretsParameterPrefix+name] = &definition.Schema{
115+
Type: "string",
116+
WriteOnly: writeOnly,
117+
}
118+
parameters[internal.SecretsParameterPrefix+name] = bundle.Parameter{
119+
Destination: &bundle.Location{
120+
Path: secret.NormalizeFilename(),
121+
},
122+
Definition: internal.SecretsParameterPrefix + name,
123+
}
124+
}
111125
var maintainers []bundle.Maintainer
112126
for _, m := range app.Metadata().Maintainers {
113127
maintainers = append(maintainers, bundle.Maintainer{

types/secrets/secrets.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package secrets
2+
3+
import (
4+
"crypto/sha256"
5+
"fmt"
6+
)
7+
8+
// Secrets represents a secret map
9+
type Secrets map[string]Secret
10+
11+
// Secret represents a secret
12+
type Secret struct {
13+
Path string
14+
External bool
15+
Name string
16+
}
17+
18+
// New creates a new empty secret map
19+
func New() Secrets {
20+
return make(map[string]Secret)
21+
}
22+
23+
// NormalizeFilename generates a filename for this secret to be mounted in the invocation image
24+
func (s *Secret) NormalizeFilename() string {
25+
digest := sha256.Sum256([]byte(s.Path))
26+
return fmt.Sprintf("/cnab/app/secret/%x", digest)
27+
}

types/types.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ import (
99
"path/filepath"
1010
"strings"
1111

12+
composeloader "github.com/docker/cli/cli/compose/loader"
13+
composetypes "github.com/docker/cli/cli/compose/types"
14+
1215
"github.com/docker/app/internal"
1316
"github.com/docker/app/types/metadata"
1417
"github.com/docker/app/types/parameters"
18+
"github.com/docker/app/types/secrets"
1519
)
1620

1721
// AppSourceKind represents what format the app was in when read
@@ -41,6 +45,7 @@ type App struct {
4145
composesContent [][]byte
4246
parametersContent [][]byte
4347
parameters parameters.Parameters
48+
secrets secrets.Secrets
4449
metadataContent []byte
4550
metadata metadata.AppMetadata
4651
attachments []Attachment
@@ -93,6 +98,11 @@ func (a *App) Attachments() []Attachment {
9398
return a.attachments
9499
}
95100

101+
// Secrets returns a map of secrets
102+
func (a *App) Secrets() secrets.Secrets {
103+
return a.secrets
104+
}
105+
96106
func (a *App) HasCRLF() bool {
97107
return a.hasCRLF
98108
}
@@ -288,10 +298,36 @@ func composeLoader(f func() ([][]byte, error)) func(app *App) error {
288298
return err
289299
}
290300
app.composesContent = append(app.composesContent, composesContent...)
301+
app.secrets = secrets.New()
302+
for _, c := range app.composesContent {
303+
parsedCompose, err := composeloader.ParseYAML(c)
304+
if err != nil {
305+
return err
306+
}
307+
cfg, err := composeloader.Load(composetypes.ConfigDetails{
308+
ConfigFiles: []composetypes.ConfigFile{
309+
{Filename: "docker-compose.yml", Config: parsedCompose},
310+
},
311+
}, withSkipInterpolation)
312+
if err != nil {
313+
return err
314+
}
315+
for name, secret := range cfg.Secrets {
316+
app.secrets[name] = secrets.Secret{
317+
Name: secret.Name,
318+
Path: secret.File,
319+
External: secret.External.External,
320+
}
321+
}
322+
}
291323
return nil
292324
}
293325
}
294326

327+
func withSkipInterpolation(opts *composeloader.Options) {
328+
opts.SkipInterpolation = true
329+
}
330+
295331
func readReaders(readers ...io.Reader) ([][]byte, error) {
296332
content := make([][]byte, len(readers))
297333
var errs []string

0 commit comments

Comments
 (0)