-
Notifications
You must be signed in to change notification settings - Fork 0
/
agent_env.go
132 lines (120 loc) · 4.11 KB
/
agent_env.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package agentcommon
import (
"crypto"
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
agentclient "github.com/stephenzsy/small-kms/backend/agent/client"
"github.com/stephenzsy/small-kms/backend/common"
)
type AgentSlot string
const (
AgentSlotPrimary AgentSlot = "primary"
AgentSlotSecondary AgentSlot = "secondary"
LegacyAgentSlotPrimary AgentSlot = "server"
LegacyAgentSlotSecondary AgentSlot = "launcher"
)
type AgentEnv struct {
common.EnvService
slot AgentSlot
certCred *azidentity.ClientCertificateCredential
agentClient *agentclient.ClientWithResponses
azSecretsClient *azsecrets.Client
}
func NewAgentEnv(envService common.EnvService, mode AgentSlot) (env *AgentEnv, err error) {
env = &AgentEnv{
EnvService: envService,
slot: mode,
}
return env, nil
}
func ParseCertificateKeyPair(filename string) (cert *x509.Certificate, key crypto.PrivateKey, err error) {
bad := func(e error) (*x509.Certificate, crypto.PrivateKey, error) {
return nil, nil, e
}
if fileContent, err := os.ReadFile(filename); err != nil {
return bad(err)
} else {
for block, rest := pem.Decode(fileContent); block != nil; block, rest = pem.Decode(rest) {
if block.Type == "CERTIFICATE" {
if cert == nil {
if cert, err = x509.ParseCertificate(block.Bytes); err != nil {
return bad(err)
}
}
} else if block.Type == "PRIVATE KEY" {
if key, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return bad(err)
}
}
}
return cert, key, nil
}
}
func (ae *AgentEnv) CertCred() (*azidentity.ClientCertificateCredential, error) {
if ae.certCred != nil {
return ae.certCred, nil
}
if tenantID, ok := ae.RequireNonWhitespace(common.EnvKeyAzTenantID, common.IdentityEnvVarPrefixAgent); !ok {
return nil, ae.ErrMissing(common.EnvKeyAzTenantID)
} else if clientID, ok := ae.RequireNonWhitespace(common.EnvKeyAzClientID, common.IdentityEnvVarPrefixAgent); !ok {
return nil, ae.ErrMissing(common.EnvKeyAzClientID)
} else if clientCertPath, ok := ae.RequireAbsPath(common.EnvKeyAzClientCertPath, common.IdentityEnvVarPrefixAgent); !ok {
return nil, ae.ErrMissing(common.EnvKeyAzClientCertPath)
} else if cert, key, err := ParseCertificateKeyPair(clientCertPath); err != nil {
return nil, err
} else if cred, err := azidentity.NewClientCertificateCredential(
tenantID,
clientID,
[]*x509.Certificate{cert}, key, nil); err != nil {
return nil, err
} else {
ae.certCred = cred
return ae.certCred, nil
}
}
func (ae *AgentEnv) AgentClient() (*agentclient.ClientWithResponses, error) {
if ae.agentClient != nil {
return ae.agentClient, nil
}
certCred, err := ae.CertCred()
if err != nil {
return nil, err
}
if apiBaseURL, ok := ae.RequireNonWhitespace(EnvKeyAPIBaseURL, common.IdentityEnvVarPrefixApp); !ok {
return nil, fmt.Errorf("%w: %s", common.ErrMissingEnvVar, EnvKeyAPIBaseURL)
} else if apiAuthScope, ok := ae.RequireNonWhitespace(EnvKeyAPIAuthScope, common.IdentityEnvVarPrefixApp); !ok {
return nil, fmt.Errorf("%w: %s", common.ErrMissingEnvVar, EnvKeyAPIAuthScope)
} else if agentClient, err := agentclient.NewClientWithResponses(
apiBaseURL,
agentclient.WithRequestEditorFn(common.ToAzTokenCredentialRequestEditorFn(
certCred, policy.TokenRequestOptions{
Scopes: []string{apiAuthScope},
}))); err != nil {
return nil, err
} else {
ae.agentClient = agentClient
return ae.agentClient, nil
}
}
func (ae *AgentEnv) AzSecretsClient() (*azsecrets.Client, error) {
if ae.azSecretsClient != nil {
return ae.azSecretsClient, nil
}
creds, err := ae.CertCred()
if err != nil {
return nil, err
}
if endpoint, ok := ae.RequireNonWhitespace(common.EnvKeyAzKeyvaultResourceEndpoint, common.IdentityEnvVarPrefixAgent); !ok {
return nil, ae.ErrMissing(common.EnvKeyAzKeyvaultResourceEndpoint)
} else if azSecretsClient, err := azsecrets.NewClient(endpoint, creds, nil); err != nil {
return nil, err
} else {
ae.azSecretsClient = azSecretsClient
return ae.azSecretsClient, nil
}
}