/
encryptedfile_provider.go
113 lines (96 loc) · 2.75 KB
/
encryptedfile_provider.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
package provider
import (
"context"
"crypto/aes"
"crypto/cipher"
"encoding/json"
"fmt"
"time"
)
const defaultEncryptedFilePath = "/var/addon/token-config"
type EncryptedFileProvider struct {
f *FileProvider
}
type EncryptedFileProviderOptions struct {
FilePath string
RefreshPeriod time.Duration
ExpiryWindow time.Duration
Logger Logger
}
func NewEncryptedFileProvider(opts EncryptedFileProviderOptions) *EncryptedFileProvider {
opts.applyDefaults()
e := &EncryptedFileProvider{}
e.f = NewFileProvider(opts.FilePath, parseEncryptedToken, FileProviderOptions{
RefreshPeriod: opts.RefreshPeriod,
ExpiryWindow: opts.ExpiryWindow,
Logger: opts.Logger,
})
return e
}
func (e *EncryptedFileProvider) Credentials(ctx context.Context) (*Credentials, error) {
return e.f.Credentials(ctx)
}
func (o *EncryptedFileProviderOptions) applyDefaults() {
if o.ExpiryWindow == 0 {
o.ExpiryWindow = defaultExpiryWindow
}
if o.FilePath == "" {
o.FilePath = defaultEncryptedFilePath
}
if o.Logger == nil {
o.Logger = defaultLog
}
}
func parseEncryptedToken(data []byte) (*Credentials, error) {
var t encryptedToken
if err := json.Unmarshal(data, &t); err != nil {
return nil, fmt.Errorf("parse data failed: %w", err)
}
id, err := decrypt([]byte(t.AccessKeyId), []byte(t.Keyring))
if err != nil {
return nil, fmt.Errorf("parse data failed: %w", err)
}
se, err := decrypt([]byte(t.AccessKeySecret), []byte(t.Keyring))
if err != nil {
return nil, fmt.Errorf("parse data failed: %w", err)
}
st, err := decrypt([]byte(t.SecurityToken), []byte(t.Keyring))
if err != nil {
return nil, fmt.Errorf("parse data failed: %w", err)
}
exp, err := time.Parse("2006-01-02T15:04:05Z", t.Expiration)
if err != nil {
return nil, fmt.Errorf("parse expiration %s failed: %w", t.Expiration, err)
}
return &Credentials{
AccessKeyId: string(id),
AccessKeySecret: string(se),
SecurityToken: string(st),
Expiration: exp,
}, nil
}
type encryptedToken struct {
AccessKeyId string `json:"access.key.id"`
AccessKeySecret string `json:"access.key.secret"`
SecurityToken string `json:"security.token"`
Expiration string `json:"expiration"`
Keyring string `json:"keyring"`
}
func decrypt(cdata []byte, keyring []byte) ([]byte, error) {
block, err := aes.NewCipher(keyring)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
iv := cdata[:blockSize]
blockMode := cipher.NewCBCDecrypter(block, iv)
origData := make([]byte, len(cdata)-blockSize)
blockMode.CryptBlocks(origData, cdata[blockSize:])
origData = pkcs5UnPadding(origData)
return origData, nil
}
func pkcs5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}