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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
package service
import (
"fmt"
"gitlab.com/gitlab-org/gitlab-runner/helpers/vault"
"gitlab.com/gitlab-org/gitlab-runner/helpers/vault/auth_methods"
_ "gitlab.com/gitlab-org/gitlab-runner/helpers/vault/auth_methods/jwt" // register auth method
"gitlab.com/gitlab-org/gitlab-runner/helpers/vault/secret_engines"
_ "gitlab.com/gitlab-org/gitlab-runner/helpers/vault/secret_engines/kv_v1" // register secret engine
_ "gitlab.com/gitlab-org/gitlab-runner/helpers/vault/secret_engines/kv_v2" // register secret engine
)
type Auth interface {
AuthName() string
AuthPath() string
AuthData() auth_methods.Data
}
type Engine interface {
EngineName() string
EnginePath() string
}
type Secret interface {
SecretPath() string
SecretField() string
}
type Vault interface {
GetField(engineDetails Engine, secretDetails Secret) (interface{}, error)
Put(engineDetails Engine, secretDetails Secret, data map[string]interface{}) error
Delete(engineDetails Engine, secretDetails Secret) error
}
type defaultVault struct {
client vault.Client
}
var newVaultClient = vault.NewClient
func NewVault(url string, namespace string, auth Auth) (Vault, error) {
v := new(defaultVault)
err := v.initialize(url, namespace, auth)
if err != nil {
return nil, fmt.Errorf("initializing Vault service: %w", err)
}
return v, nil
}
func (v *defaultVault) initialize(url string, namespace string, auth Auth) error {
err := v.prepareAuthenticatedClient(url, namespace, auth)
if err != nil {
return fmt.Errorf("preparing authenticated client: %w", err)
}
return nil
}
func (v *defaultVault) prepareAuthenticatedClient(url string, namespace string, authDetails Auth) error {
client, err := newVaultClient(url, namespace)
if err != nil {
return err
}
auth, err := v.prepareAuthMethodAdapter(authDetails)
if err != nil {
return err
}
err = client.Authenticate(auth)
if err != nil {
return err
}
v.client = client
return nil
}
func (v *defaultVault) prepareAuthMethodAdapter(authDetails Auth) (vault.AuthMethod, error) {
authFactory, err := auth_methods.GetFactory(authDetails.AuthName())
if err != nil {
return nil, fmt.Errorf("initializing auth method factory: %w", err)
}
auth, err := authFactory(authDetails.AuthPath(), authDetails.AuthData())
if err != nil {
return nil, fmt.Errorf("initializing auth method adapter: %w", err)
}
return auth, nil
}
func (v *defaultVault) GetField(engineDetails Engine, secretDetails Secret) (interface{}, error) {
engine, err := v.getSecretEngine(engineDetails)
if err != nil {
return nil, err
}
secret, err := engine.Get(secretDetails.SecretPath())
if err != nil {
return nil, fmt.Errorf("reading secret: %w", err)
}
field := secretDetails.SecretField()
for key, data := range secret {
if key != field {
continue
}
return data, nil
}
return nil, nil
}
func (v *defaultVault) getSecretEngine(engineDetails Engine) (vault.SecretEngine, error) {
engineFactory, err := secret_engines.GetFactory(engineDetails.EngineName())
if err != nil {
return nil, fmt.Errorf("requesting SecretEngine factory: %w", err)
}
engine := engineFactory(v.client, engineDetails.EnginePath())
return engine, nil
}
func (v *defaultVault) Put(engineDetails Engine, secretDetails Secret, data map[string]interface{}) error {
engine, err := v.getSecretEngine(engineDetails)
if err != nil {
return err
}
err = engine.Put(secretDetails.SecretPath(), data)
if err != nil {
return fmt.Errorf("writing secret: %w", err)
}
return nil
}
func (v *defaultVault) Delete(engineDetails Engine, secretDetails Secret) error {
engine, err := v.getSecretEngine(engineDetails)
if err != nil {
return err
}
err = engine.Delete(secretDetails.SecretPath())
if err != nil {
return fmt.Errorf("deleting secret: %w", err)
}
return nil
}
|