Skip to content

Commit fe27b54

Browse files
committed
feat(secrets): add new package for managing secrets
Signed-off-by: Henrique Matulis <hmatulis@google.com>
1 parent 0b2fbf3 commit fe27b54

16 files changed

+2130
-1
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/julienschmidt/httprouter v1.3.0
1111
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
1212
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
13+
github.com/prometheus/client_golang v1.20.4
1314
github.com/prometheus/client_model v0.6.2
1415
github.com/stretchr/testify v1.11.1
1516
go.yaml.in/yaml/v2 v2.4.3
@@ -25,7 +26,6 @@ require (
2526
github.com/davecgh/go-spew v1.1.1 // indirect
2627
github.com/jpillora/backoff v1.0.0 // indirect
2728
github.com/pmezard/go-difflib v1.0.0 // indirect
28-
github.com/prometheus/client_golang v1.20.4 // indirect
2929
github.com/prometheus/procfs v0.15.1 // indirect
3030
github.com/rogpeppe/go-internal v1.10.0 // indirect
3131
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect

secrets/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Secret Management
2+
3+
The `secrets` package provides a unified way to handle secrets within configuration files for Prometheus and its ecosystem components. It allows secrets to be specified inline, loaded from files, or fetched from other sources through a pluggable provider mechanism.
4+
5+
See the rendered [GoDoc here](https://pkg.go.dev/github.com/prometheus/common/secrets) if on GitHub.
6+
7+
## How to Use
8+
9+
Using the `secrets` package involves three main steps: defining your configuration struct, initializing the secret manager, and accessing the secret values. Refer to the [package example GoDoc](https://pkg.go.dev/github.com/prometheus/common/secrets#example-package).
10+
11+
12+
## Built-in Providers
13+
14+
The `secrets` package comes with two built-in providers: `inline` and `file`. For more details, please refer to the [GoDoc](https://pkg.go.dev/github.com/prometheus/common/secrets#pkg-variables).
15+
16+
## Custom Providers
17+
18+
You can extend the functionality by creating your own custom secret providers. For a detailed guide on creating custom providers, please refer to the [GoDoc for the `Provider` and `ProviderConfig` interfaces](https://pkg.go.dev/github.com/prometheus/common/secrets#Provider).

secrets/doc.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2025 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
// Package secrets provides a unified way to handle secrets within
15+
// configuration files for Prometheus and its ecosystem components. It allows
16+
// secrets to be specified inline, loaded from files, or fetched from other
17+
// sources through a pluggable provider mechanism.
18+
package secrets

secrets/example_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2025 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package secrets_test
15+
16+
import (
17+
"context"
18+
"fmt"
19+
"os"
20+
"time"
21+
22+
"github.com/prometheus/client_golang/prometheus"
23+
"go.yaml.in/yaml/v2"
24+
25+
"github.com/prometheus/common/secrets"
26+
)
27+
28+
func Example() {
29+
// A Prometheus registry is needed to register the secret manager's metrics.
30+
promRegisterer := prometheus.NewRegistry()
31+
32+
// Create a temporary file to simulate a file-based secret (e.g., Kubernetes mount).
33+
passwordFile, err := os.CreateTemp("", "password_secret")
34+
if err != nil {
35+
panic(err)
36+
}
37+
defer os.Remove(passwordFile.Name())
38+
39+
if _, err := passwordFile.WriteString("my_super_secret_password"); err != nil {
40+
passwordFile.Close()
41+
panic(err)
42+
}
43+
passwordFile.Close()
44+
45+
// In your configuration struct, use the `secrets.Field` type for any fields
46+
// that should contain secrets.
47+
type MyConfig struct {
48+
APIKey secrets.Field `yaml:"api_key"`
49+
Password secrets.Field `yaml:"password"`
50+
}
51+
52+
// Users can then provide secrets in their YAML configuration file.
53+
// We inject the temporary file path created above.
54+
configData := []byte(fmt.Sprintf(`
55+
api_key: "my_super_secret_api_key"
56+
password:
57+
file:
58+
path: %s
59+
`, passwordFile.Name()))
60+
61+
var cfg MyConfig
62+
if err := yaml.Unmarshal(configData, &cfg); err != nil {
63+
panic(fmt.Errorf("error unmarshaling config: %w", err))
64+
}
65+
66+
// Create a secret manager. This discovers and manages all Fields in cfg.
67+
// The manager will handle refreshing secrets in the background.
68+
manager, err := secrets.NewManager(promRegisterer, secrets.Providers, &cfg)
69+
if err != nil {
70+
panic(fmt.Errorf("error creating secret manager: %w", err))
71+
}
72+
73+
// Start the manager's background refresh loop.
74+
manager.Start(context.Background())
75+
defer manager.Stop()
76+
77+
// Wait for the secrets in cfg to be resolved and ready.
78+
for {
79+
ready, err := manager.SecretsReady(&cfg)
80+
if err != nil {
81+
panic(fmt.Errorf("error checking secret readiness: %w", err))
82+
}
83+
if ready {
84+
break
85+
}
86+
// Prevent a busy loop while waiting for I/O
87+
time.Sleep(100 * time.Millisecond)
88+
}
89+
90+
// Access the secret values.
91+
apiKey := cfg.APIKey.Get()
92+
password := cfg.Password.Get()
93+
94+
fmt.Printf("API Key: %s\n", apiKey)
95+
fmt.Printf("Password: %s\n", password)
96+
97+
// Output:
98+
// API Key: my_super_secret_api_key
99+
// Password: my_super_secret_password
100+
}

0 commit comments

Comments
 (0)