Skip to content

Commit

Permalink
pre-generate a ready-to-use dockerconfig json
Browse files Browse the repository at this point in the history
  • Loading branch information
xrstf committed Oct 11, 2021
1 parent eb4cc46 commit 0ef55d8
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 6 deletions.
6 changes: 4 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ type RobotConfig struct {
// secret where the token should be stored, for example
// "mykvstore/data/customer-xyz" (note the "/data/" bit).
// Aquayman will extend the secret with a
// "quay.io-<orgname>-token" key and store the token there.
// "quay.io-<orgname>-token" and a "quay.io-<orgname>-secret" keys
// and store the token / a full docker config JSON there.
// If this is empty, no Vault interaction happens, even
// if -enable-vault is set.
// The value can include an optional key name to override
// the default. Use a "#" to separate path from key, e.g.
// "mykvstore/data/customer-xyz#keyname".
// "mykvstore/data/customer-xyz#keyname". Aquayman will still
// append "-token" and "-secret" to the custom keyname.
VaultSecret string `yaml:"vaultSecret,omitempty"`

// Deleted can be used as a workaround for deleting tokens
Expand Down
61 changes: 57 additions & 4 deletions pkg/publisher/vault.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package publisher

import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"strings"

Expand Down Expand Up @@ -44,6 +47,12 @@ func (v *Vault) UpdateRobot(ctx context.Context, robot *config.RobotConfig, toke
return fmt.Errorf("failed to read from Vault: %w", err)
}

// precalculate a nice to use docker pull config JSON file
configJson, err := v.getDockerConfig(robot, token)
if err != nil {
return fmt.Errorf("failed to create Docker config: %w", err)
}

secretUpToDate := false
existingData := map[string]interface{}{}

Expand All @@ -55,17 +64,27 @@ func (v *Vault) UpdateRobot(ctx context.Context, robot *config.RobotConfig, toke
if m, ok := data.(map[string]interface{}); ok {
existingData = m

if value, exists := m[addr.key]; exists {
if value, exists := m[addr.key+"-token"]; exists {
if svalue, ok := value.(string); ok {
secretUpToDate = svalue == token
}
}

if secretUpToDate {
if value, exists := m[addr.key+"-config"]; exists {
if svalue, ok := value.(string); ok {
secretUpToDate = svalue == configJson
}
}
}
}
}
}

if !secretUpToDate {
existingData[addr.key] = token
existingData[addr.key+"-token"] = token
existingData[addr.key+"-config"] = configJson

secret.Data["data"] = existingData

if _, err := v.client.Logical().Write(addr.path, secret.Data); err != nil {
Expand All @@ -76,6 +95,39 @@ func (v *Vault) UpdateRobot(ctx context.Context, robot *config.RobotConfig, toke
return nil
}

type dockerConfig struct {
Auths map[string]dockerAuth `json:"auths"`
}

type dockerAuth struct {
Auth string `json:"auth"`
Email string `json:"email"`
}

func (v *Vault) getDockerConfig(robot *config.RobotConfig, token string) (string, error) {
auth := fmt.Sprintf("%s+%s:%s", v.org, robot.Name, token)
encoded := base64.StdEncoding.EncodeToString([]byte(auth))

cfg := dockerConfig{
Auths: map[string]dockerAuth{
"quay.io": {
Auth: encoded,
},
},
}

var buf bytes.Buffer

encoder := json.NewEncoder(&buf)
encoder.SetIndent("", " ")

if err := encoder.Encode(cfg); err != nil {
return "", fmt.Errorf("failed to encode docker config as JSON: %w", err)
}

return buf.String(), nil
}

func (v *Vault) DeleteRobot(ctx context.Context, robot *config.RobotConfig) error {
if robot.VaultSecret == "" {
return nil
Expand All @@ -102,7 +154,8 @@ func (v *Vault) DeleteRobot(ctx context.Context, robot *config.RobotConfig) erro
if data, exists := secret.Data["data"]; exists {
if m, ok := data.(map[string]interface{}); ok {
if _, exists := m[addr.key]; exists {
delete(m, addr.key)
delete(m, addr.key+"-token")
delete(m, addr.key+"-config")

secret.Data["data"] = m

Expand All @@ -129,7 +182,7 @@ func (v *Vault) getAddress(robot *config.RobotConfig) (*address, error) {

a := address{
path: parts[0],
key: fmt.Sprintf("quay.io-%s-%s-token", v.org, robot.Name),
key: fmt.Sprintf("quay.io-%s-%s", v.org, robot.Name),
}

if len(parts) > 1 {
Expand Down

0 comments on commit 0ef55d8

Please sign in to comment.