Skip to content

Commit fe95dc0

Browse files
committed
Implement modular cloudprovider
Signed-off-by: Markus Blaschke <mblaschke82@gmail.com>
1 parent 567959a commit fe95dc0

File tree

6 files changed

+227
-174
lines changed

6 files changed

+227
-174
lines changed
Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package manager
1+
package bootstraptoken
22

33
import (
44
"fmt"
@@ -8,40 +8,40 @@ import (
88
)
99

1010
type (
11-
bootstrapToken struct {
11+
BootstrapToken struct {
1212
id string
1313
secret string
1414
creationTime *time.Time
1515
expirationTime *time.Time
1616
}
1717
)
1818

19-
func (t *bootstrapToken) Id() string {
19+
func (t *BootstrapToken) Id() string {
2020
return t.id
2121
}
2222

23-
func (t *bootstrapToken) Secret() string {
23+
func (t *BootstrapToken) Secret() string {
2424
return t.secret
2525
}
2626

27-
func (t *bootstrapToken) FullToken() string {
27+
func (t *BootstrapToken) FullToken() string {
2828
return fmt.Sprintf("%s.%s", t.id, t.secret)
2929
}
3030

31-
func (t *bootstrapToken) SetExpirationTime(val time.Time) {
31+
func (t *BootstrapToken) SetExpirationTime(val time.Time) {
3232
t.expirationTime = &val
3333
}
3434

35-
func (t *bootstrapToken) SetExpirationUnixTime(val date.UnixTime) {
35+
func (t *BootstrapToken) SetExpirationUnixTime(val date.UnixTime) {
3636
expirationTime := date.UnixEpoch().Add(val.Duration())
3737
t.expirationTime = &expirationTime
3838
}
3939

40-
func (t *bootstrapToken) GetExpirationTime() *time.Time {
40+
func (t *BootstrapToken) GetExpirationTime() *time.Time {
4141
return t.expirationTime
4242
}
4343

44-
func (t *bootstrapToken) ExpirationString() (expiration string) {
44+
func (t *BootstrapToken) ExpirationString() (expiration string) {
4545
expiration = "<not set>"
4646
if t.expirationTime != nil {
4747
expiration = fmt.Sprintf(
@@ -54,47 +54,47 @@ func (t *bootstrapToken) ExpirationString() (expiration string) {
5454
return
5555
}
5656

57-
func (t *bootstrapToken) GetExpirationUnixTime() (val *date.UnixTime) {
57+
func (t *BootstrapToken) GetExpirationUnixTime() (val *date.UnixTime) {
5858
if t.expirationTime != nil {
5959
unixTime := date.NewUnixTimeFromDuration(t.expirationTime.Sub(date.UnixEpoch()))
6060
val = &unixTime
6161
}
6262
return
6363
}
6464

65-
func (t *bootstrapToken) SetCreationTime(val time.Time) {
65+
func (t *BootstrapToken) SetCreationTime(val time.Time) {
6666
t.creationTime = &val
6767
}
6868

69-
func (t *bootstrapToken) SetCreationUnixTime(val date.UnixTime) {
69+
func (t *BootstrapToken) SetCreationUnixTime(val date.UnixTime) {
7070
creationTime := date.UnixEpoch().Add(val.Duration())
7171
t.creationTime = &creationTime
7272
}
7373

74-
func (t *bootstrapToken) GetCreationTime() *time.Time {
74+
func (t *BootstrapToken) GetCreationTime() *time.Time {
7575
return t.creationTime
7676
}
7777

78-
func (t *bootstrapToken) GetCreationUnixTime() (val *date.UnixTime) {
78+
func (t *BootstrapToken) GetCreationUnixTime() (val *date.UnixTime) {
7979
if t.creationTime != nil {
8080
unixTime := date.NewUnixTimeFromDuration(t.creationTime.Sub(date.UnixEpoch()))
8181
val = &unixTime
8282
}
8383
return
8484
}
8585

86-
func newBootstrapToken(id, secret string) *bootstrapToken {
87-
token := bootstrapToken{
86+
func NewBootstrapToken(id, secret string) *BootstrapToken {
87+
token := BootstrapToken{
8888
id: id,
8989
secret: secret,
9090
}
9191
return &token
9292
}
9393

94-
func parseBootstrapTokenFromString(value string) *bootstrapToken {
94+
func ParseFromString(value string) *BootstrapToken {
9595
tokenParts := strings.SplitN(value, ".", 2)
9696
if len(tokenParts) == 2 {
97-
token := bootstrapToken{
97+
token := BootstrapToken{
9898
id: tokenParts[0],
9999
secret: tokenParts[1],
100100
}

cloudprovider/azure.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package cloudprovider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
7+
"github.com/Azure/go-autorest/autorest"
8+
"github.com/Azure/go-autorest/autorest/azure"
9+
"github.com/Azure/go-autorest/autorest/azure/auth"
10+
log "github.com/sirupsen/logrus"
11+
"github.com/webdevops/kube-bootstrap-token-manager/bootstraptoken"
12+
"github.com/webdevops/kube-bootstrap-token-manager/config"
13+
)
14+
15+
type (
16+
CloudProviderAzure struct {
17+
CloudProvider
18+
19+
opts config.Opts
20+
ctx context.Context
21+
22+
log *log.Entry
23+
environment azure.Environment
24+
authorizer autorest.Authorizer
25+
26+
keyvaultClient *keyvault.BaseClient
27+
}
28+
)
29+
30+
func (m *CloudProviderAzure) Init(ctx context.Context, opts config.Opts) {
31+
var err error
32+
m.ctx = ctx
33+
m.opts = opts
34+
m.log = log.WithField("cloudprovider", "azure")
35+
36+
// environment
37+
if m.opts.CloudProvider.Config != nil {
38+
m.environment, err = azure.EnvironmentFromFile(*m.opts.CloudProvider.Config)
39+
} else if m.opts.CloudProvider.Azure.Environment != nil {
40+
m.environment, err = azure.EnvironmentFromName(*m.opts.CloudProvider.Azure.Environment)
41+
} else {
42+
m.environment, err = azure.EnvironmentFromName("AZUREPUBLICCLOUD")
43+
}
44+
if err != nil {
45+
m.log.Panic(err)
46+
}
47+
48+
// auth
49+
if m.opts.CloudProvider.Config != nil {
50+
m.authorizer, err = auth.NewAuthorizerFromFile(m.environment.ResourceIdentifiers.KeyVault)
51+
} else {
52+
m.authorizer, err = auth.NewAuthorizerFromEnvironmentWithResource(m.environment.ResourceIdentifiers.KeyVault)
53+
}
54+
if err != nil {
55+
m.log.Panic(err)
56+
}
57+
}
58+
59+
func (m *CloudProviderAzure) FetchToken() (token *bootstraptoken.BootstrapToken) {
60+
if m.opts.CloudProvider.Azure.KeyVaultName != nil && m.opts.CloudProvider.Azure.KeyVaultSecretName != nil {
61+
vaultName := *m.opts.CloudProvider.Azure.KeyVaultName
62+
secretName := *m.opts.CloudProvider.Azure.KeyVaultSecretName
63+
vaultUrl := fmt.Sprintf(
64+
"https://%s.%s",
65+
vaultName,
66+
m.environment.KeyVaultDNSSuffix,
67+
)
68+
69+
log.Infof("fetching newest token from Azure KeyVault \"%s\" secret \"%s\"", vaultName, secretName)
70+
secret, err := m.azureKeyvaultClient().GetSecret(m.ctx, vaultUrl, secretName, "")
71+
if !secret.IsHTTPStatus(404) && err != nil {
72+
log.Panic(err)
73+
}
74+
75+
if secret.Value != nil {
76+
token = bootstraptoken.ParseFromString(*secret.Value)
77+
if token != nil {
78+
if secret.Attributes.Created != nil {
79+
token.SetCreationUnixTime(*secret.Attributes.Created)
80+
}
81+
82+
if secret.Attributes.Expires != nil {
83+
token.SetExpirationUnixTime(*secret.Attributes.Expires)
84+
}
85+
}
86+
}
87+
}
88+
89+
if token != nil {
90+
contextLogger := log.WithFields(log.Fields{"token": token.Id()})
91+
contextLogger.Infof("found cloud token with id \"%s\" and expiration %s", token.Id(), token.ExpirationString())
92+
}
93+
94+
return
95+
}
96+
97+
func (m *CloudProviderAzure) StoreToken(token *bootstraptoken.BootstrapToken) {
98+
contextLogger := m.log.WithFields(log.Fields{"token": token.Id()})
99+
if m.opts.CloudProvider.Azure.KeyVaultName != nil && m.opts.CloudProvider.Azure.KeyVaultSecretName != nil {
100+
vaultName := *m.opts.CloudProvider.Azure.KeyVaultName
101+
secretName := *m.opts.CloudProvider.Azure.KeyVaultSecretName
102+
vaultUrl := fmt.Sprintf(
103+
"https://%s.%s",
104+
vaultName,
105+
m.environment.KeyVaultDNSSuffix,
106+
)
107+
108+
contextLogger.Infof("storing token to Azure KeyVault \"%s\" secret \"%s\" with expiration %s", vaultName, secretName, token.ExpirationString())
109+
110+
secretParameters := keyvault.SecretSetParameters{
111+
Value: stringPtr(token.FullToken()),
112+
Tags: map[string]*string{
113+
"managed-by": stringPtr("kube-bootstrap-token-manager"),
114+
"token": stringPtr(token.Id()),
115+
},
116+
ContentType: stringPtr("kube-bootstrap-token"),
117+
SecretAttributes: &keyvault.SecretAttributes{
118+
NotBefore: token.GetCreationUnixTime(),
119+
Expires: token.GetExpirationUnixTime(),
120+
},
121+
}
122+
_, err := m.azureKeyvaultClient().SetSecret(m.ctx, vaultUrl, secretName, secretParameters)
123+
if err != nil {
124+
log.Panic(err)
125+
}
126+
}
127+
}
128+
129+
func (m *CloudProviderAzure) azureKeyvaultClient() *keyvault.BaseClient {
130+
if m.keyvaultClient == nil {
131+
auth, err := auth.NewAuthorizerFromEnvironmentWithResource(m.environment.ResourceIdentifiers.KeyVault)
132+
if err != nil {
133+
log.Panic(err)
134+
}
135+
136+
client := keyvault.New()
137+
client.Authorizer = auth
138+
m.keyvaultClient = &client
139+
}
140+
141+
return m.keyvaultClient
142+
}

cloudprovider/base.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package cloudprovider
2+
3+
import (
4+
"context"
5+
log "github.com/sirupsen/logrus"
6+
"github.com/webdevops/kube-bootstrap-token-manager/bootstraptoken"
7+
"github.com/webdevops/kube-bootstrap-token-manager/config"
8+
)
9+
10+
type (
11+
CloudProvider interface {
12+
Init(ctx context.Context, opts config.Opts)
13+
FetchToken() (token *bootstraptoken.BootstrapToken)
14+
StoreToken(token *bootstraptoken.BootstrapToken)
15+
}
16+
)
17+
18+
func NewCloudProvider(provider string) CloudProvider {
19+
switch provider {
20+
case "azure":
21+
return &CloudProviderAzure{}
22+
}
23+
24+
log.Panicf("Cloud provider \"%s\" not available", provider)
25+
return nil
26+
}

manager/misc.go renamed to cloudprovider/misc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package manager
1+
package cloudprovider
22

33
func stringPtr(val string) *string {
44
return &val

config/opts.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type (
1616
}
1717

1818
BootstrapToken struct {
19+
TemplateId string `long:"bootstraptoken.template-id" env:"BOOTSTRAPTOKEN_TEMPLATE_ID" description:"Name for bootstrap tokens" default:"{{.Date}}"`
1920
Name string `long:"bootstraptoken.name" env:"BOOTSTRAPTOKEN_NAME" description:"Name for bootstrap tokens" default:"bootstrap-token-%s"`
2021
Label string `long:"bootstraptoken.label" env:"BOOTSTRAPTOKEN_LABEL" description:"Label for bootstrap tokens" default:"webdevops.kubernetes.io/bootstraptoken-managed"`
2122
Namespace string `long:"bootstraptoken.namespace" env:"BOOTSTRAPTOKEN_NAMESPACE" description:"Namespace for bootstrap tokens" default:"kube-system"`

0 commit comments

Comments
 (0)