Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/julienschmidt/httprouter v1.3.0
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
github.com/prometheus/client_golang v1.20.4
github.com/prometheus/client_model v0.6.2
github.com/stretchr/testify v1.11.1
go.yaml.in/yaml/v2 v2.4.3
Expand All @@ -25,7 +26,6 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.20.4 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
Expand Down
18 changes: 18 additions & 0 deletions secrets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Secret Management
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

One thing to discuss/put in README.

How it relates to

type Secret string

What would be the plan forward? Deprecate config.Secret?


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.

See the rendered [GoDoc here](https://pkg.go.dev/github.com/prometheus/common/secrets) if on GitHub.

## How to Use

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).


## Built-in Providers

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).

## Custom Providers

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).
18 changes: 18 additions & 0 deletions secrets/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package secrets 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.
package secrets
100 changes: 100 additions & 0 deletions secrets/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package secrets_test

import (
"context"
"fmt"
"os"
"time"

"github.com/prometheus/client_golang/prometheus"
"go.yaml.in/yaml/v2"

"github.com/prometheus/common/secrets"
)

func Example() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

nit: We likely want some name for this example to make this wrong, but maybe it works like that too? Happy to merge and learn.

Suggested change
func Example() {
func ExampleSecretsUse() {

// A Prometheus registry is needed to register the secret manager's metrics.
promRegisterer := prometheus.NewRegistry()

// Create a temporary file to simulate a file-based secret (e.g., Kubernetes mount).
passwordFile, err := os.CreateTemp("", "password_secret")
if err != nil {
panic(err)
}
defer os.Remove(passwordFile.Name())

if _, err := passwordFile.WriteString("my_super_secret_password"); err != nil {
passwordFile.Close()
panic(err)
}
passwordFile.Close()

// In your configuration struct, use the `secrets.Field` type for any fields
// that should contain secrets.
type MyConfig struct {
APIKey secrets.Field `yaml:"api_key"`
Password secrets.Field `yaml:"password"`
}

// Users can then provide secrets in their YAML configuration file.
// We inject the temporary file path created above.
configData := []byte(fmt.Sprintf(`
api_key: "my_super_secret_api_key"
password:
file:
path: %s
`, passwordFile.Name()))

var cfg MyConfig
if err := yaml.Unmarshal(configData, &cfg); err != nil {
panic(fmt.Errorf("error unmarshaling config: %w", err))
}

// Create a secret manager. This discovers and manages all Fields in cfg.
// The manager will handle refreshing secrets in the background.
manager, err := secrets.NewManager(promRegisterer, secrets.Providers, &cfg)
if err != nil {
panic(fmt.Errorf("error creating secret manager: %w", err))
}

// Start the manager's background refresh loop.
manager.Start(context.Background())
defer manager.Stop()

// Wait for the secrets in cfg to be resolved and ready.
for {
ready, err := manager.SecretsReady(&cfg)
if err != nil {
panic(fmt.Errorf("error checking secret readiness: %w", err))
}
if ready {
break
}
// Prevent a busy loop while waiting for I/O
time.Sleep(100 * time.Millisecond)
}

// Access the secret values.
apiKey := cfg.APIKey.Get()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very cool use!

password := cfg.Password.Get()

fmt.Printf("API Key: %s\n", apiKey)
fmt.Printf("Password: %s\n", password)

// Output:
// API Key: my_super_secret_api_key
// Password: my_super_secret_password
}
Loading
Loading