Commit 7082ce05 authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

Merge branch 'master' into 'master'

fix: escape dot character in vault key

Closes #11

See merge request to-be-continuous/tools/vault-secrets-provider!23
parents 216b05f0 fef23e9d
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ test-on-local:
    - curl -sSf "$VAULT_BASE_URL/sys/health"
    # create a secret in Vault
    - |
      curl --silent --header "X-Vault-Token: ${VAULT_DEV_ROOT_TOKEN_ID}" --request PUT --data '{"data": {"foo": "bar", "zip": "zap"}}' "${VAULT_BASE_URL}/secret/data/my-secret"
      curl --silent --header "X-Vault-Token: ${VAULT_DEV_ROOT_TOKEN_ID}" --request PUT --data '{"data": {"foo": "bar", "zip": "zap", "dede.1": "toto"}}' "${VAULT_BASE_URL}/secret/data/my-secret"
    # test: get existing secret shall succeed
    - |
      resp_status=$(curl -s -o "resp.txt" -w "%{http_code}" "http://vault-secrets-provider/api/secrets/my-secret?field=foo")
@@ -94,6 +94,14 @@ test-on-local:
        cat resp.txt
        exit 1
      fi
    # test: get existing secret with escaping character shall succeed
    - |
      resp_status=$(curl -s -o "resp.txt" -w "%{http_code}" "http://vault-secrets-provider/api/secrets/my-secret?field=dede\.1")
      if [[ "$resp_status" != "200" ]]; then
        echo "FAILED get existing secret ($resp_status)"
        cat resp.txt
        exit 1
      fi
    # test: get secret with non existing path shall fail with code 404
    - |
      resp_status=$(curl -s -o "resp.txt" -w "%{http_code}" "http://vault-secrets-provider/api/secrets/no/such/path?field=foo")
+5 −1
Original line number Diff line number Diff line
@@ -60,14 +60,18 @@ Let's suppose your have a secret stored under `/b7ecb6ebabc231/my-backend/prod`
  "mysql": {
    "user": "root",
    "password": "p@s5w0rd"
  }
  },
  "golang.nickname": "Go"
}
```

> :warning: You can use `\` as an escape character when a secret key contains `.`

Then you may retrieve:

* the token calling `GET http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/my-backend/prod?field=token`
* the MySql password calling `GET http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/my-backend/prod?field=mysql.password`
* the Golang nickname calling `GET http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/my-backend/prod?field=golang\.nickname`

#### PUT secret endpoint

+12 −1
Original line number Diff line number Diff line
@@ -565,13 +565,24 @@ func doDeleteSecret(secretPath string) error {
	}
}

// splitWithEscaping slices s into all substrings separated by sep and returns a slice of the substrings between those separators.
// It considers an escape character for separator
func splitWithEscaping(s, sep, escape string) []string {
	s = strings.ReplaceAll(s, escape+sep, `\x00`)
	subStrings := strings.Split(s, sep)
	for i, subString := range subStrings {
		subStrings[i] = strings.ReplaceAll(subString, `\x00`, sep)
	}
	return subStrings
}

/**
 * Retrieves a sub object within a map
 * @arg obj: a map object
 * @arg keyPath: dot separated keys path (ex: '.', 'path.to.field')
 */
func getObj(obj map[string]interface{}, keyPath string) (string, error) {
	keys := strings.Split(keyPath, ".")
	keys := splitWithEscaping(keyPath, ".", `\`)
	var sub interface{}
	sub = obj
	for index := 0; index < len(keys); index++ {
+18 −0
Original line number Diff line number Diff line
@@ -75,6 +75,24 @@ func Test_get_sub_map(t *testing.T) {
	}
}

func Test_get_sub_key_with_dot(t *testing.T) {
	obj := map[string]interface{}{
		"key": "value",
		"map": map[string]interface{}{
			"k1.1": "111",
			"k2":   "222",
			"k3":   "333",
		},
	}
	path := `map.k1\.1`
	expected := `111`
	if sub, err := getObj(obj, path); err != nil {
		t.Fatalf("Error retrieving sub object: %v", err)
	} else if sub != expected {
		t.Fatalf("Assert error\nExpected:\n%s\nGot:\n%s", string(expected), string(sub))
	}
}

func Test_get_sub_sub_key(t *testing.T) {
	obj := map[string]interface{}{
		"key": "value",