github.com/jenkins-x/jx/v2@v2.1.155/pkg/vault/vault.go (about) 1 package vault 2 3 import ( 4 "fmt" 5 6 "github.com/jenkins-x/jx/v2/pkg/errorutil" 7 "github.com/jenkins-x/jx/v2/pkg/util" 8 "github.com/pkg/errors" 9 ) 10 11 const ( 12 // SystemVaultName stores the name of the Vault instance created and managed by Jenkins X unless an external Vault 13 // instance is used in which case this name will be empty. 14 SystemVaultName = "systemVaultName" 15 16 // URL stores the URL of the external Vault instance if no system internal Vault instance is used. 17 URL = "vaultURL" 18 19 // ServiceAccount stores the name of the service account used to connect to Vault. 20 ServiceAccount = "vaultServiceAccount" 21 22 // Namespace stores the service account namespace which is allowed to connect to Vault. 23 Namespace = "vaultNamespace" 24 25 // SecretEngineMountPoint defines the Vault mount point for the KV secret engine. 26 SecretEngineMountPoint = "vaultSecretEngineMountPoint" 27 28 // KubernetesAuthPath defines the path under which the Kubernetes auth method is configured. 29 KubernetesAuthPath = "vaultKubernetesAuthPath" 30 31 // DefaultKVEngineMountPoint default mount point for the KV V2 engine 32 DefaultKVEngineMountPoint = "secret" 33 34 // DefaultKubernetesAuthPath is the default Kubernetes auth path 35 DefaultKubernetesAuthPath = "kubernetes" 36 37 // defaultServiceAccountSuffix is the default suffix appended to the Vault name if no service account name is specified. 38 defaultServiceAccountSuffix = "-vt" 39 ) 40 41 // Vault stores the required information to connect and authenticate against a Vault instance. 42 type Vault struct { 43 // Name defines the name of the Vault instance, provided we are dealing with an Jenkins X managed Vault instance 44 Name string 45 46 // ServiceAccountName is the name of the service account allowed to authenticate against Vault. 47 ServiceAccountName string 48 49 // Namespace of the service account authorized to authenticate against Vault. 50 Namespace string 51 52 // URL specifies the Vault URL to connect to. 53 URL string 54 55 // SecretEngineMountPoint is the mount point to be used for writing data into the KV engine. 56 SecretEngineMountPoint string 57 58 // KubernetesAuthPath is the path under which the Vault Kubernetes auth method is configured. 59 KubernetesAuthPath string 60 } 61 62 // NewExternalVault creates an external Vault instance configuration from the provided parameters. 63 func NewExternalVault(url string, serviceAccountName string, namespace string, secretEngineMountPoint string, kubernetesAuthPath string) (Vault, error) { 64 if url == "" { 65 return Vault{}, errors.New("URL cannot be empty for an external Vault configuration") 66 } 67 68 data := map[string]string{} 69 70 data[SystemVaultName] = "" 71 data[URL] = url 72 data[ServiceAccount] = serviceAccountName 73 data[Namespace] = namespace 74 data[SecretEngineMountPoint] = secretEngineMountPoint 75 data[KubernetesAuthPath] = kubernetesAuthPath 76 77 return FromMap(data, namespace) 78 } 79 80 // NewInternalVault creates an internal Vault instance configuration from the provided parameters. 81 func NewInternalVault(name string, serviceAccountName string, namespace string) (Vault, error) { 82 if name == "" { 83 return Vault{}, errors.New("name cannot be empty for an internal Vault configuration") 84 } 85 86 if serviceAccountName == "" { 87 serviceAccountName = fmt.Sprintf("%s-%s", name, defaultServiceAccountSuffix) 88 } 89 90 data := map[string]string{} 91 data[SystemVaultName] = name 92 data[ServiceAccount] = serviceAccountName 93 data[Namespace] = namespace 94 95 return FromMap(data, namespace) 96 } 97 98 // FromMap reads the configuration of a Vault instance from a map. 99 // defaultNamespace is used when there is no namespace value provided in the map (for backwards compatibility reasons). 100 func FromMap(data map[string]string, defaultNamespace string) (Vault, error) { 101 if data[SystemVaultName] != "" && data[URL] != "" { 102 return Vault{}, errors.New("systemVaultName and URL cannot be specified together") 103 } 104 105 secretEngineMountPoint := data[SecretEngineMountPoint] 106 if secretEngineMountPoint == "" { 107 secretEngineMountPoint = DefaultKVEngineMountPoint 108 } 109 110 kubernetesAuthPath := data[KubernetesAuthPath] 111 if kubernetesAuthPath == "" { 112 kubernetesAuthPath = DefaultKubernetesAuthPath 113 } 114 115 namespace := data[Namespace] 116 if namespace == "" { 117 namespace = defaultNamespace 118 } 119 120 vault := Vault{ 121 Name: data[SystemVaultName], 122 URL: data[URL], 123 ServiceAccountName: data[ServiceAccount], 124 Namespace: namespace, 125 SecretEngineMountPoint: secretEngineMountPoint, 126 KubernetesAuthPath: kubernetesAuthPath, 127 } 128 129 var err error 130 external := vault.IsExternal() 131 if external { 132 err = vault.validateExternalConfiguration() 133 } else { 134 err = vault.validateInternalConfiguration() 135 } 136 137 return vault, err 138 } 139 140 // IsExternal returns true if the Vault instance represents an externally managed Vault instance or one managed by Jenkins X. 141 func (v *Vault) IsExternal() bool { 142 if v.URL == "" { 143 return false 144 } 145 return true 146 } 147 148 // ToMap writes the configuration of this Vault instance to a map 149 func (v *Vault) ToMap() map[string]string { 150 data := map[string]string{} 151 152 data[SystemVaultName] = v.Name 153 data[URL] = v.URL 154 data[ServiceAccount] = v.ServiceAccountName 155 data[Namespace] = v.Namespace 156 data[SecretEngineMountPoint] = v.SecretEngineMountPoint 157 data[KubernetesAuthPath] = v.KubernetesAuthPath 158 159 return data 160 } 161 162 // validateExternalConfiguration validates the values of the Vault configuration for an external Vault setup. 163 func (v *Vault) validateExternalConfiguration() error { 164 var validationErrors []error 165 var err error 166 if v.URL == "" { 167 return errors.New("URL cannot be empty") 168 } 169 170 if v.URL != "" && !util.IsValidUrl(v.URL) { 171 err = errors.Errorf("'%s' not a valid URL", v.URL) 172 validationErrors = append(validationErrors, err) 173 } 174 175 if v.ServiceAccountName == "" { 176 err = errors.New("external vault service account name cannot be empty") 177 validationErrors = append(validationErrors, err) 178 } 179 180 if v.Namespace == "" { 181 err = errors.New("external vault namespace cannot be empty") 182 validationErrors = append(validationErrors, err) 183 } 184 185 if v.SecretEngineMountPoint == "" { 186 err = errors.New("external vault secret engine mount point cannot be empty") 187 validationErrors = append(validationErrors, err) 188 } 189 190 if v.KubernetesAuthPath == "" { 191 err = errors.New("external vault Kubernetes auth path cannot be empty") 192 validationErrors = append(validationErrors, err) 193 } 194 return errorutil.CombineErrors(validationErrors...) 195 } 196 197 // validateInternalConfiguration validates the values of the Vault configuration for an internal, Jenkins X managed, Vault setup. 198 func (v *Vault) validateInternalConfiguration() error { 199 var validationErrors []error 200 var err error 201 if v.Name == "" { 202 err = errors.New("internal vault name cannot be empty") 203 validationErrors = append(validationErrors, err) 204 } 205 206 if v.ServiceAccountName == "" { 207 err = errors.New("internal vault service account name cannot be empty") 208 validationErrors = append(validationErrors, err) 209 } 210 211 if v.Namespace == "" { 212 err = errors.New("internal vault namespace cannot be empty") 213 validationErrors = append(validationErrors, err) 214 } 215 216 return errorutil.CombineErrors(validationErrors...) 217 }