-
Notifications
You must be signed in to change notification settings - Fork 98
/
creds.go
112 lines (91 loc) · 2.65 KB
/
creds.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-2021 Datadog, Inc.
package config
import (
"errors"
"os"
"sync"
"time"
"github.com/DataDog/datadog-operator/pkg/secrets"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
)
// Creds holds the api and app keys.
type Creds struct {
APIKey string
AppKey string
}
// CredentialManager provides the credentials from the operator configuration.
type CredentialManager struct {
secretBackend secrets.Decryptor
creds Creds
credsMutex sync.Mutex
decryptorBackoff wait.Backoff
}
// NewCredentialManager returns a CredentialManager.
func NewCredentialManager() *CredentialManager {
return &CredentialManager{
secretBackend: secrets.NewSecretBackend(),
creds: Creds{},
decryptorBackoff: wait.Backoff{
Steps: 5,
Duration: 10 * time.Millisecond,
Factor: 5.0,
Cap: 20 * time.Second,
},
}
}
// GetCredentials returns the API and APP keys respectively from the operator configurations.
// This function tries to decrypt the secrets using the secret backend if needed.
// It returns an error if the creds aren't configured or if the secret backend fails to decrypt.
func (cm *CredentialManager) GetCredentials() (Creds, error) {
if creds, found := cm.getCredsFromCache(); found {
return creds, nil
}
apiKey := os.Getenv(DDAPIKeyEnvVar)
appKey := os.Getenv(DDAppKeyEnvVar)
if apiKey == "" || appKey == "" {
return Creds{}, errors.New("empty API key and/or App key")
}
var encrypted []string
if secrets.IsEnc(apiKey) {
encrypted = append(encrypted, apiKey)
}
if secrets.IsEnc(appKey) {
encrypted = append(encrypted, appKey)
}
if len(encrypted) > 0 {
decrypted := map[string]string{}
var decErr error
if err := retry.OnError(cm.decryptorBackoff, secrets.Retriable, func() error {
decrypted, decErr = cm.secretBackend.Decrypt(encrypted)
return decErr
}); err != nil {
return Creds{}, err
}
if val, found := decrypted[apiKey]; found {
apiKey = val
}
if val, found := decrypted[appKey]; found {
appKey = val
}
}
creds := Creds{APIKey: apiKey, AppKey: appKey}
cm.cacheCreds(creds)
return creds, nil
}
func (cm *CredentialManager) cacheCreds(creds Creds) {
cm.credsMutex.Lock()
defer cm.credsMutex.Unlock()
cm.creds = creds
}
func (cm *CredentialManager) getCredsFromCache() (Creds, bool) {
cm.credsMutex.Lock()
defer cm.credsMutex.Unlock()
if cm.creds.APIKey != "" && cm.creds.AppKey != "" {
return cm.creds, true
}
return Creds{}, false
}