Avoid envs and extend CRDs with vault config; remove controller dependency completely
This commit is contained in:
		
							parent
							
								
									69dfa4e375
								
							
						
					
					
						commit
						c3ce54cabc
					
				|  | @ -59,7 +59,10 @@ type AutoscalingListenerSpec struct { | |||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubServerTLS *GitHubServerTLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 	GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Metrics *MetricsConfig `json:"metrics,omitempty"` | ||||
|  | @ -98,7 +101,7 @@ func (l *AutoscalingListener) Proxy() *ProxyConfig { | |||
| 	return l.Spec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (l *AutoscalingListener) GitHubServerTLS() *GitHubServerTLSConfig { | ||||
| func (l *AutoscalingListener) GitHubServerTLS() *TLSConfig { | ||||
| 	return l.Spec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/actions/actions-runner-controller/hash" | ||||
| 	"github.com/actions/actions-runner-controller/vault" | ||||
| 	"golang.org/x/net/http/httpproxy" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
|  | @ -69,7 +70,13 @@ type AutoscalingRunnerSetSpec struct { | |||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubServerTLS *GitHubServerTLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 	GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultServerTLS *TLSConfig `json:"vaultServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	Template corev1.PodTemplateSpec `json:"template,omitempty"` | ||||
|  | @ -89,12 +96,12 @@ type AutoscalingRunnerSetSpec struct { | |||
| 	MinRunners *int `json:"minRunners,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type GitHubServerTLSConfig struct { | ||||
| type TLSConfig struct { | ||||
| 	// Required
 | ||||
| 	CertificateFrom *TLSCertificateSource `json:"certificateFrom,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (c *GitHubServerTLSConfig) ToCertPool(keyFetcher func(name, key string) ([]byte, error)) (*x509.CertPool, error) { | ||||
| func (c *TLSConfig) ToCertPool(keyFetcher func(name, key string) ([]byte, error)) (*x509.CertPool, error) { | ||||
| 	if c.CertificateFrom == nil { | ||||
| 		return nil, fmt.Errorf("certificateFrom not specified") | ||||
| 	} | ||||
|  | @ -235,6 +242,26 @@ type ProxyServerConfig struct { | |||
| 	CredentialSecretRef string `json:"credentialSecretRef,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type VaultConfig struct { | ||||
| 	// +optional
 | ||||
| 	Type vault.VaultType `json:"type,omitempty"` | ||||
| 	// +optional
 | ||||
| 	AzureKeyVault *AzureKeyVaultConfig `json:"azureKeyVault,omitempty"` | ||||
| 	// +optional
 | ||||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type AzureKeyVaultConfig struct { | ||||
| 	// +required
 | ||||
| 	URL string `json:"url,omitempty"` | ||||
| 	// +required
 | ||||
| 	TenantID string `json:"tenantId,omitempty"` | ||||
| 	// +required
 | ||||
| 	ClientID string `json:"clientId,omitempty"` | ||||
| 	// +required
 | ||||
| 	CertificatePath string `json:"certificatePath,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // MetricsConfig holds configuration parameters for each metric type
 | ||||
| type MetricsConfig struct { | ||||
| 	// +optional
 | ||||
|  | @ -293,11 +320,15 @@ func (ars *AutoscalingRunnerSet) GitHubConfigUrl() string { | |||
| 	return ars.Spec.GitHubConfigUrl | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) VaultConfig() *VaultConfig { | ||||
| 	return ars.Spec.VaultConfig | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) Proxy() *ProxyConfig { | ||||
| 	return ars.Spec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) GitHubServerTLS() *GitHubServerTLSConfig { | ||||
| func (ars *AutoscalingRunnerSet) GitHubServerTLS() *TLSConfig { | ||||
| 	return ars.Spec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
|  | @ -308,7 +339,7 @@ func (ars *AutoscalingRunnerSet) RunnerSetSpecHash() string { | |||
| 		RunnerGroup        string | ||||
| 		RunnerScaleSetName string | ||||
| 		Proxy              *ProxyConfig | ||||
| 		GitHubServerTLS    *GitHubServerTLSConfig | ||||
| 		GitHubServerTLS    *TLSConfig | ||||
| 		Template           corev1.PodTemplateSpec | ||||
| 	} | ||||
| 	spec := &runnerSetSpec{ | ||||
|  |  | |||
|  | @ -79,10 +79,14 @@ func (er *EphemeralRunner) Proxy() *ProxyConfig { | |||
| 	return er.Spec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) GitHubServerTLS() *GitHubServerTLSConfig { | ||||
| func (er *EphemeralRunner) GitHubServerTLS() *TLSConfig { | ||||
| 	return er.Spec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
| func (ars *EphemeralRunner) VaultConfig() *VaultConfig { | ||||
| 	return ars.Spec.VaultConfig | ||||
| } | ||||
| 
 | ||||
| // EphemeralRunnerSpec defines the desired state of EphemeralRunner
 | ||||
| type EphemeralRunnerSpec struct { | ||||
| 	// +required
 | ||||
|  | @ -101,7 +105,10 @@ type EphemeralRunnerSpec struct { | |||
| 	ProxySecretRef string `json:"proxySecretRef,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubServerTLS *GitHubServerTLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 	GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` | ||||
| 
 | ||||
| 	corev1.PodTemplateSpec `json:",inline"` | ||||
| } | ||||
|  |  | |||
|  | @ -72,10 +72,14 @@ func (ers *EphemeralRunnerSet) Proxy() *ProxyConfig { | |||
| 	return ers.Spec.EphemeralRunnerSpec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) GitHubServerTLS() *GitHubServerTLSConfig { | ||||
| func (ers *EphemeralRunnerSet) GitHubServerTLS() *TLSConfig { | ||||
| 	return ers.Spec.EphemeralRunnerSpec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
| func (ars *EphemeralRunnerSet) VaultConfig() *VaultConfig { | ||||
| 	return ars.Spec.EphemeralRunnerSpec.VaultConfig | ||||
| } | ||||
| 
 | ||||
| // EphemeralRunnerSetList contains a list of EphemeralRunnerSet
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| type EphemeralRunnerSetList struct { | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ import ( | |||
| 
 | ||||
| func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) { | ||||
| 	t.Run("returns an error if CertificateFrom not specified", func(t *testing.T) { | ||||
| 		c := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 		c := &v1alpha1.TLSConfig{ | ||||
| 			CertificateFrom: nil, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -29,7 +29,7 @@ func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) { | |||
| 	}) | ||||
| 
 | ||||
| 	t.Run("returns an error if CertificateFrom.ConfigMapKeyRef not specified", func(t *testing.T) { | ||||
| 		c := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 		c := &v1alpha1.TLSConfig{ | ||||
| 			CertificateFrom: &v1alpha1.TLSCertificateSource{}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -41,7 +41,7 @@ func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) { | |||
| 	}) | ||||
| 
 | ||||
| 	t.Run("returns a valid cert pool with correct configuration", func(t *testing.T) { | ||||
| 		c := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 		c := &v1alpha1.TLSConfig{ | ||||
| 			CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 				ConfigMapKeyRef: &v1.ConfigMapKeySelector{ | ||||
| 					LocalObjectReference: v1.LocalObjectReference{ | ||||
|  |  | |||
|  | @ -100,7 +100,12 @@ func (in *AutoscalingListenerSpec) DeepCopyInto(out *AutoscalingListenerSpec) { | |||
| 	} | ||||
| 	if in.GitHubServerTLS != nil { | ||||
| 		in, out := &in.GitHubServerTLS, &out.GitHubServerTLS | ||||
| 		*out = new(GitHubServerTLSConfig) | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultConfig != nil { | ||||
| 		in, out := &in.VaultConfig, &out.VaultConfig | ||||
| 		*out = new(VaultConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.Metrics != nil { | ||||
|  | @ -209,7 +214,17 @@ func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec) | |||
| 	} | ||||
| 	if in.GitHubServerTLS != nil { | ||||
| 		in, out := &in.GitHubServerTLS, &out.GitHubServerTLS | ||||
| 		*out = new(GitHubServerTLSConfig) | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultServerTLS != nil { | ||||
| 		in, out := &in.VaultServerTLS, &out.VaultServerTLS | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultConfig != nil { | ||||
| 		in, out := &in.VaultConfig, &out.VaultConfig | ||||
| 		*out = new(VaultConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	in.Template.DeepCopyInto(&out.Template) | ||||
|  | @ -260,6 +275,21 @@ func (in *AutoscalingRunnerSetStatus) DeepCopy() *AutoscalingRunnerSetStatus { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AzureKeyVaultConfig) DeepCopyInto(out *AzureKeyVaultConfig) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureKeyVaultConfig.
 | ||||
| func (in *AzureKeyVaultConfig) DeepCopy() *AzureKeyVaultConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AzureKeyVaultConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *CounterMetric) DeepCopyInto(out *CounterMetric) { | ||||
| 	*out = *in | ||||
|  | @ -439,7 +469,12 @@ func (in *EphemeralRunnerSpec) DeepCopyInto(out *EphemeralRunnerSpec) { | |||
| 	} | ||||
| 	if in.GitHubServerTLS != nil { | ||||
| 		in, out := &in.GitHubServerTLS, &out.GitHubServerTLS | ||||
| 		*out = new(GitHubServerTLSConfig) | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultConfig != nil { | ||||
| 		in, out := &in.VaultConfig, &out.VaultConfig | ||||
| 		*out = new(VaultConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	in.PodTemplateSpec.DeepCopyInto(&out.PodTemplateSpec) | ||||
|  | @ -497,26 +532,6 @@ func (in *GaugeMetric) DeepCopy() *GaugeMetric { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *GitHubServerTLSConfig) DeepCopyInto(out *GitHubServerTLSConfig) { | ||||
| 	*out = *in | ||||
| 	if in.CertificateFrom != nil { | ||||
| 		in, out := &in.CertificateFrom, &out.CertificateFrom | ||||
| 		*out = new(TLSCertificateSource) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubServerTLSConfig.
 | ||||
| func (in *GitHubServerTLSConfig) DeepCopy() *GitHubServerTLSConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(GitHubServerTLSConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *HistogramMetric) DeepCopyInto(out *HistogramMetric) { | ||||
| 	*out = *in | ||||
|  | @ -669,3 +684,48 @@ func (in *TLSCertificateSource) DeepCopy() *TLSCertificateSource { | |||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { | ||||
| 	*out = *in | ||||
| 	if in.CertificateFrom != nil { | ||||
| 		in, out := &in.CertificateFrom, &out.CertificateFrom | ||||
| 		*out = new(TLSCertificateSource) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
 | ||||
| func (in *TLSConfig) DeepCopy() *TLSConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(TLSConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *VaultConfig) DeepCopyInto(out *VaultConfig) { | ||||
| 	*out = *in | ||||
| 	if in.AzureKeyVault != nil { | ||||
| 		in, out := &in.AzureKeyVault, &out.AzureKeyVault | ||||
| 		*out = new(AzureKeyVaultConfig) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.Proxy != nil { | ||||
| 		in, out := &in.Proxy, &out.Proxy | ||||
| 		*out = new(ProxyConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultConfig.
 | ||||
| func (in *VaultConfig) DeepCopy() *VaultConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(VaultConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
|  |  | |||
|  | @ -7863,6 +7863,53 @@ spec: | |||
|                         - containers | ||||
|                       type: object | ||||
|                   type: object | ||||
|                 vaultConfig: | ||||
|                   properties: | ||||
|                     azureKeyVault: | ||||
|                       properties: | ||||
|                         certificatePath: | ||||
|                           type: string | ||||
|                         clientId: | ||||
|                           type: string | ||||
|                         tenantId: | ||||
|                           type: string | ||||
|                         url: | ||||
|                           type: string | ||||
|                       required: | ||||
|                         - certificatePath | ||||
|                         - clientId | ||||
|                         - tenantId | ||||
|                         - url | ||||
|                       type: object | ||||
|                     proxy: | ||||
|                       properties: | ||||
|                         http: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         https: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         noProxy: | ||||
|                           items: | ||||
|                             type: string | ||||
|                           type: array | ||||
|                       type: object | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         VaultType represents the type of vault that can be used in the application. | ||||
|                         It is used to identify which vault integration should be used to resolve secrets. | ||||
|                       type: string | ||||
|                   type: object | ||||
|               type: object | ||||
|             status: | ||||
|               description: AutoscalingListenerStatus defines the observed state of AutoscalingListener | ||||
|  |  | |||
|  | @ -15504,6 +15504,82 @@ spec: | |||
|                         - containers | ||||
|                       type: object | ||||
|                   type: object | ||||
|                 vaultConfig: | ||||
|                   properties: | ||||
|                     azureKeyVault: | ||||
|                       properties: | ||||
|                         certificatePath: | ||||
|                           type: string | ||||
|                         clientId: | ||||
|                           type: string | ||||
|                         tenantId: | ||||
|                           type: string | ||||
|                         url: | ||||
|                           type: string | ||||
|                       required: | ||||
|                         - certificatePath | ||||
|                         - clientId | ||||
|                         - tenantId | ||||
|                         - url | ||||
|                       type: object | ||||
|                     proxy: | ||||
|                       properties: | ||||
|                         http: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         https: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         noProxy: | ||||
|                           items: | ||||
|                             type: string | ||||
|                           type: array | ||||
|                       type: object | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         VaultType represents the type of vault that can be used in the application. | ||||
|                         It is used to identify which vault integration should be used to resolve secrets. | ||||
|                       type: string | ||||
|                   type: object | ||||
|                 vaultServerTLS: | ||||
|                   properties: | ||||
|                     certificateFrom: | ||||
|                       description: Required | ||||
|                       properties: | ||||
|                         configMapKeyRef: | ||||
|                           description: Required | ||||
|                           properties: | ||||
|                             key: | ||||
|                               description: The key to select. | ||||
|                               type: string | ||||
|                             name: | ||||
|                               default: "" | ||||
|                               description: |- | ||||
|                                 Name of the referent. | ||||
|                                 This field is effectively required, but due to backwards compatibility is | ||||
|                                 allowed to be empty. Instances of this type with an empty value here are | ||||
|                                 almost certainly wrong. | ||||
|                                 More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names | ||||
|                               type: string | ||||
|                             optional: | ||||
|                               description: Specify whether the ConfigMap or its key must be defined | ||||
|                               type: boolean | ||||
|                           required: | ||||
|                             - key | ||||
|                           type: object | ||||
|                           x-kubernetes-map-type: atomic | ||||
|                       type: object | ||||
|                   type: object | ||||
|               type: object | ||||
|             status: | ||||
|               description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet | ||||
|  |  | |||
|  | @ -7784,6 +7784,53 @@ spec: | |||
|                   required: | ||||
|                     - containers | ||||
|                   type: object | ||||
|                 vaultConfig: | ||||
|                   properties: | ||||
|                     azureKeyVault: | ||||
|                       properties: | ||||
|                         certificatePath: | ||||
|                           type: string | ||||
|                         clientId: | ||||
|                           type: string | ||||
|                         tenantId: | ||||
|                           type: string | ||||
|                         url: | ||||
|                           type: string | ||||
|                       required: | ||||
|                         - certificatePath | ||||
|                         - clientId | ||||
|                         - tenantId | ||||
|                         - url | ||||
|                       type: object | ||||
|                     proxy: | ||||
|                       properties: | ||||
|                         http: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         https: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         noProxy: | ||||
|                           items: | ||||
|                             type: string | ||||
|                           type: array | ||||
|                       type: object | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         VaultType represents the type of vault that can be used in the application. | ||||
|                         It is used to identify which vault integration should be used to resolve secrets. | ||||
|                       type: string | ||||
|                   type: object | ||||
|               required: | ||||
|                 - githubConfigSecret | ||||
|                 - githubConfigUrl | ||||
|  |  | |||
|  | @ -7778,6 +7778,53 @@ spec: | |||
|                       required: | ||||
|                         - containers | ||||
|                       type: object | ||||
|                     vaultConfig: | ||||
|                       properties: | ||||
|                         azureKeyVault: | ||||
|                           properties: | ||||
|                             certificatePath: | ||||
|                               type: string | ||||
|                             clientId: | ||||
|                               type: string | ||||
|                             tenantId: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               type: string | ||||
|                           required: | ||||
|                             - certificatePath | ||||
|                             - clientId | ||||
|                             - tenantId | ||||
|                             - url | ||||
|                           type: object | ||||
|                         proxy: | ||||
|                           properties: | ||||
|                             http: | ||||
|                               properties: | ||||
|                                 credentialSecretRef: | ||||
|                                   type: string | ||||
|                                 url: | ||||
|                                   description: Required | ||||
|                                   type: string | ||||
|                               type: object | ||||
|                             https: | ||||
|                               properties: | ||||
|                                 credentialSecretRef: | ||||
|                                   type: string | ||||
|                                 url: | ||||
|                                   description: Required | ||||
|                                   type: string | ||||
|                               type: object | ||||
|                             noProxy: | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                           type: object | ||||
|                         type: | ||||
|                           description: |- | ||||
|                             VaultType represents the type of vault that can be used in the application. | ||||
|                             It is used to identify which vault integration should be used to resolve secrets. | ||||
|                           type: string | ||||
|                       type: object | ||||
|                   required: | ||||
|                     - githubConfigSecret | ||||
|                     - githubConfigUrl | ||||
|  |  | |||
|  | @ -66,6 +66,24 @@ spec: | |||
|     {{- end }} | ||||
|   {{- end }} | ||||
| 
 | ||||
|   {{- if and .Values.keyVault .Values.keyVault.type }} | ||||
|   vaultConfig: | ||||
|     type: {{ .Values.keyVault.type }} | ||||
|     {{- if eq .Values.keyVault.type "azure_key_vault" }} | ||||
|     azureKeyVault: | ||||
|       url: {{ .Values.keyVault.azureKeyVault.url }} | ||||
|       tenantId: {{ .Values.keyVault.azureKeyVault.tenantId }} | ||||
|       clientId: {{ .Values.keyVault.azureKeyVault.clientId }} | ||||
|       certificatePath: {{ .Values.keyVault.azureKeyVault.certificatePath }} | ||||
|       secretKey: {{ .Values.keyVault.azureKeyVault.secretKey }} | ||||
|       {{- if .Values.keyVault.azureKeyVault.proxy }} | ||||
|       proxy: {{- toYaml .Values.keyVault.azureKeyVault.proxy | nindent 6 }} | ||||
|       {{- end }} | ||||
|     {{- else }} | ||||
|     {{- fail "Unsupported vaultConfig type: " .Values.vaultConfig.type }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| 
 | ||||
|   {{- if .Values.proxy }} | ||||
|   proxy: | ||||
|     {{- if .Values.proxy.http }} | ||||
|  |  | |||
|  | @ -1158,7 +1158,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) { | |||
| 			ars := render(t, options) | ||||
| 
 | ||||
| 			require.NotNil(t, ars.Spec.GitHubServerTLS) | ||||
| 			expected := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			expected := &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1218,7 +1218,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) { | |||
| 			ars := render(t, options) | ||||
| 
 | ||||
| 			require.NotNil(t, ars.Spec.GitHubServerTLS) | ||||
| 			expected := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			expected := &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1278,7 +1278,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) { | |||
| 			ars := render(t, options) | ||||
| 
 | ||||
| 			require.NotNil(t, ars.Spec.GitHubServerTLS) | ||||
| 			expected := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			expected := &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1338,7 +1338,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) { | |||
| 			ars := render(t, options) | ||||
| 
 | ||||
| 			require.NotNil(t, ars.Spec.GitHubServerTLS) | ||||
| 			expected := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			expected := &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1394,7 +1394,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) { | |||
| 			ars := render(t, options) | ||||
| 
 | ||||
| 			require.NotNil(t, ars.Spec.GitHubServerTLS) | ||||
| 			expected := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			expected := &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1450,7 +1450,7 @@ func TestTemplateRenderedWithTLS(t *testing.T) { | |||
| 			ars := render(t, options) | ||||
| 
 | ||||
| 			require.NotNil(t, ars.Spec.GitHubServerTLS) | ||||
| 			expected := &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			expected := &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  |  | |||
|  | @ -88,6 +88,27 @@ githubConfigSecret: | |||
| #       key: ca.crt | ||||
| #   runnerMountPath: /usr/local/share/ca-certificates/ | ||||
| 
 | ||||
| # keyVault: | ||||
|   # Available values: "azure_key_vault" | ||||
|   # type: "" | ||||
|   # Configuration related to azure key vault | ||||
|   # azure_key_vault: | ||||
|   #   url: "" | ||||
|   #   client_id: "" | ||||
|   #   tenant_id: "" | ||||
|   #   certificate_path: "" | ||||
|     # proxy: | ||||
|     #   http: | ||||
|     #     url: http://proxy.com:1234 | ||||
|     #     credentialSecretRef: proxy-auth # a secret with `username` and `password` keys | ||||
|     #   https: | ||||
|     #     url: http://proxy.com:1234 | ||||
|     #     credentialSecretRef: proxy-auth # a secret with `username` and `password` keys | ||||
|     #   noProxy: | ||||
|     #     - example.com | ||||
|     #     - example.org | ||||
| 
 | ||||
| 
 | ||||
| ## Container mode is an object that provides out-of-box configuration | ||||
| ## for dind and kubernetes mode. Template will be modified as documented under the | ||||
| ## template object. | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ import ( | |||
| 	"github.com/actions/actions-runner-controller/github/actions" | ||||
| 	"github.com/actions/actions-runner-controller/logging" | ||||
| 	"github.com/actions/actions-runner-controller/vault" | ||||
| 	"github.com/actions/actions-runner-controller/vault/azurekeyvault" | ||||
| 	"github.com/go-logr/logr" | ||||
| 	"golang.org/x/net/http/httpproxy" | ||||
| ) | ||||
|  | @ -23,6 +24,8 @@ type Config struct { | |||
| 	ConfigureUrl   string          `json:"configure_url"` | ||||
| 	VaultType      vault.VaultType `json:"vault_type"` | ||||
| 	VaultLookupKey string          `json:"vault_lookup_key"` | ||||
| 	// If the VaultType is set to "azure_key_vault", this field must be populated.
 | ||||
| 	AzureKeyVaultConfig *azurekeyvault.Config `json:"azure_key_vault,omitempty"` | ||||
| 	// AppConfig contains the GitHub App configuration.
 | ||||
| 	// It is initially set to nil if VaultType is set.
 | ||||
| 	// Otherwise, it is populated with the GitHub App credentials from the GitHub secret.
 | ||||
|  | @ -53,31 +56,28 @@ func Read(ctx context.Context, configPath string) (*Config, error) { | |||
| 		return nil, fmt.Errorf("failed to decode config: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if config.VaultType == "" { | ||||
| 	var vault vault.Vault | ||||
| 	switch config.VaultType { | ||||
| 	case "": | ||||
| 		if err := config.Validate(); err != nil { | ||||
| 			return nil, fmt.Errorf("failed to validate configuration: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		return &config, nil | ||||
| 	} | ||||
| 	case "azure_key_vault": | ||||
| 		akv, err := azurekeyvault.New(*config.AzureKeyVaultConfig) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to create Azure Key Vault client: %w", err) | ||||
| 		} | ||||
| 
 | ||||
| 	if config.VaultLookupKey == "" { | ||||
| 		panic(fmt.Errorf("vault type set to %q, but lookup key is empty", config.VaultType)) | ||||
| 	} | ||||
| 
 | ||||
| 	vaults, err := vault.InitAll("LISTENER_") | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to initialize vaults: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	vault, ok := vaults[config.VaultType] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("vault %q is not initialized", config.VaultType) | ||||
| 		vault = akv | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unsupported vault type: %s", config.VaultType) | ||||
| 	} | ||||
| 
 | ||||
| 	appConfigRaw, err := vault.GetSecret(ctx, config.VaultLookupKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return nil, fmt.Errorf("failed to get app config from vault: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	appConfig, err := appconfig.FromString(appConfigRaw) | ||||
|  |  | |||
|  | @ -7863,6 +7863,53 @@ spec: | |||
|                         - containers | ||||
|                       type: object | ||||
|                   type: object | ||||
|                 vaultConfig: | ||||
|                   properties: | ||||
|                     azureKeyVault: | ||||
|                       properties: | ||||
|                         certificatePath: | ||||
|                           type: string | ||||
|                         clientId: | ||||
|                           type: string | ||||
|                         tenantId: | ||||
|                           type: string | ||||
|                         url: | ||||
|                           type: string | ||||
|                       required: | ||||
|                         - certificatePath | ||||
|                         - clientId | ||||
|                         - tenantId | ||||
|                         - url | ||||
|                       type: object | ||||
|                     proxy: | ||||
|                       properties: | ||||
|                         http: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         https: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         noProxy: | ||||
|                           items: | ||||
|                             type: string | ||||
|                           type: array | ||||
|                       type: object | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         VaultType represents the type of vault that can be used in the application. | ||||
|                         It is used to identify which vault integration should be used to resolve secrets. | ||||
|                       type: string | ||||
|                   type: object | ||||
|               type: object | ||||
|             status: | ||||
|               description: AutoscalingListenerStatus defines the observed state of AutoscalingListener | ||||
|  |  | |||
|  | @ -15504,6 +15504,82 @@ spec: | |||
|                         - containers | ||||
|                       type: object | ||||
|                   type: object | ||||
|                 vaultConfig: | ||||
|                   properties: | ||||
|                     azureKeyVault: | ||||
|                       properties: | ||||
|                         certificatePath: | ||||
|                           type: string | ||||
|                         clientId: | ||||
|                           type: string | ||||
|                         tenantId: | ||||
|                           type: string | ||||
|                         url: | ||||
|                           type: string | ||||
|                       required: | ||||
|                         - certificatePath | ||||
|                         - clientId | ||||
|                         - tenantId | ||||
|                         - url | ||||
|                       type: object | ||||
|                     proxy: | ||||
|                       properties: | ||||
|                         http: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         https: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         noProxy: | ||||
|                           items: | ||||
|                             type: string | ||||
|                           type: array | ||||
|                       type: object | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         VaultType represents the type of vault that can be used in the application. | ||||
|                         It is used to identify which vault integration should be used to resolve secrets. | ||||
|                       type: string | ||||
|                   type: object | ||||
|                 vaultServerTLS: | ||||
|                   properties: | ||||
|                     certificateFrom: | ||||
|                       description: Required | ||||
|                       properties: | ||||
|                         configMapKeyRef: | ||||
|                           description: Required | ||||
|                           properties: | ||||
|                             key: | ||||
|                               description: The key to select. | ||||
|                               type: string | ||||
|                             name: | ||||
|                               default: "" | ||||
|                               description: |- | ||||
|                                 Name of the referent. | ||||
|                                 This field is effectively required, but due to backwards compatibility is | ||||
|                                 allowed to be empty. Instances of this type with an empty value here are | ||||
|                                 almost certainly wrong. | ||||
|                                 More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names | ||||
|                               type: string | ||||
|                             optional: | ||||
|                               description: Specify whether the ConfigMap or its key must be defined | ||||
|                               type: boolean | ||||
|                           required: | ||||
|                             - key | ||||
|                           type: object | ||||
|                           x-kubernetes-map-type: atomic | ||||
|                       type: object | ||||
|                   type: object | ||||
|               type: object | ||||
|             status: | ||||
|               description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet | ||||
|  |  | |||
|  | @ -7784,6 +7784,53 @@ spec: | |||
|                   required: | ||||
|                     - containers | ||||
|                   type: object | ||||
|                 vaultConfig: | ||||
|                   properties: | ||||
|                     azureKeyVault: | ||||
|                       properties: | ||||
|                         certificatePath: | ||||
|                           type: string | ||||
|                         clientId: | ||||
|                           type: string | ||||
|                         tenantId: | ||||
|                           type: string | ||||
|                         url: | ||||
|                           type: string | ||||
|                       required: | ||||
|                         - certificatePath | ||||
|                         - clientId | ||||
|                         - tenantId | ||||
|                         - url | ||||
|                       type: object | ||||
|                     proxy: | ||||
|                       properties: | ||||
|                         http: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         https: | ||||
|                           properties: | ||||
|                             credentialSecretRef: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               description: Required | ||||
|                               type: string | ||||
|                           type: object | ||||
|                         noProxy: | ||||
|                           items: | ||||
|                             type: string | ||||
|                           type: array | ||||
|                       type: object | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         VaultType represents the type of vault that can be used in the application. | ||||
|                         It is used to identify which vault integration should be used to resolve secrets. | ||||
|                       type: string | ||||
|                   type: object | ||||
|               required: | ||||
|                 - githubConfigSecret | ||||
|                 - githubConfigUrl | ||||
|  |  | |||
|  | @ -7778,6 +7778,53 @@ spec: | |||
|                       required: | ||||
|                         - containers | ||||
|                       type: object | ||||
|                     vaultConfig: | ||||
|                       properties: | ||||
|                         azureKeyVault: | ||||
|                           properties: | ||||
|                             certificatePath: | ||||
|                               type: string | ||||
|                             clientId: | ||||
|                               type: string | ||||
|                             tenantId: | ||||
|                               type: string | ||||
|                             url: | ||||
|                               type: string | ||||
|                           required: | ||||
|                             - certificatePath | ||||
|                             - clientId | ||||
|                             - tenantId | ||||
|                             - url | ||||
|                           type: object | ||||
|                         proxy: | ||||
|                           properties: | ||||
|                             http: | ||||
|                               properties: | ||||
|                                 credentialSecretRef: | ||||
|                                   type: string | ||||
|                                 url: | ||||
|                                   description: Required | ||||
|                                   type: string | ||||
|                               type: object | ||||
|                             https: | ||||
|                               properties: | ||||
|                                 credentialSecretRef: | ||||
|                                   type: string | ||||
|                                 url: | ||||
|                                   description: Required | ||||
|                                   type: string | ||||
|                               type: object | ||||
|                             noProxy: | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                           type: object | ||||
|                         type: | ||||
|                           description: |- | ||||
|                             VaultType represents the type of vault that can be used in the application. | ||||
|                             It is used to identify which vault integration should be used to resolve secrets. | ||||
|                           type: string | ||||
|                       type: object | ||||
|                   required: | ||||
|                     - githubConfigSecret | ||||
|                     - githubConfigUrl | ||||
|  |  | |||
|  | @ -1065,7 +1065,7 @@ var _ = Describe("Test GitHub Server TLS configuration", func() { | |||
| 			Spec: v1alpha1.AutoscalingRunnerSetSpec{ | ||||
| 				GitHubConfigUrl:    "https://github.com/owner/repo", | ||||
| 				GitHubConfigSecret: configSecret.Name, | ||||
| 				GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{ | ||||
| 				GitHubServerTLS: &v1alpha1.TLSConfig{ | ||||
| 					CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 						ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 							LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1101,7 +1101,7 @@ var _ = Describe("Test GitHub Server TLS configuration", func() { | |||
| 			Spec: v1alpha1.AutoscalingListenerSpec{ | ||||
| 				GitHubConfigUrl:    "https://github.com/owner/repo", | ||||
| 				GitHubConfigSecret: configSecret.Name, | ||||
| 				GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{ | ||||
| 				GitHubServerTLS: &v1alpha1.TLSConfig{ | ||||
| 					CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 						ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 							LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  |  | |||
|  | @ -1201,7 +1201,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() { | |||
| 				Spec: v1alpha1.AutoscalingRunnerSetSpec{ | ||||
| 					GitHubConfigUrl:    server.ConfigURLForOrg("my-org"), | ||||
| 					GitHubConfigSecret: configSecret.Name, | ||||
| 					GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{ | ||||
| 					GitHubServerTLS: &v1alpha1.TLSConfig{ | ||||
| 						CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 							ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 								LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1254,7 +1254,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() { | |||
| 				Spec: v1alpha1.AutoscalingRunnerSetSpec{ | ||||
| 					GitHubConfigUrl:    "https://github.com/owner/repo", | ||||
| 					GitHubConfigSecret: configSecret.Name, | ||||
| 					GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{ | ||||
| 					GitHubServerTLS: &v1alpha1.TLSConfig{ | ||||
| 						CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 							ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 								LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  | @ -1318,7 +1318,7 @@ var _ = Describe("Test client optional configuration", Ordered, func() { | |||
| 				Spec: v1alpha1.AutoscalingRunnerSetSpec{ | ||||
| 					GitHubConfigUrl:    "https://github.com/owner/repo", | ||||
| 					GitHubConfigSecret: configSecret.Name, | ||||
| 					GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{ | ||||
| 					GitHubServerTLS: &v1alpha1.TLSConfig{ | ||||
| 						CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 							ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 								LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  |  | |||
|  | @ -43,8 +43,6 @@ const ( | |||
| 	AnnotationKeyGitHubRunnerGroupName    = "actions.github.com/runner-group-name" | ||||
| 	AnnotationKeyGitHubRunnerScaleSetName = "actions.github.com/runner-scale-set-name" | ||||
| 	AnnotationKeyPatchID                  = "actions.github.com/patch-id" | ||||
| 
 | ||||
| 	AnnotationKeyGitHubVaultType = "actions.github.com/vault" | ||||
| ) | ||||
| 
 | ||||
| // Labels applied to listener roles
 | ||||
|  |  | |||
|  | @ -1093,7 +1093,7 @@ var _ = Describe("EphemeralRunner", func() { | |||
| 
 | ||||
| 			ephemeralRunner := newExampleRunner("test-runner", autoScalingNS.Name, configSecret.Name) | ||||
| 			ephemeralRunner.Spec.GitHubConfigUrl = server.ConfigURLForOrg("my-org") | ||||
| 			ephemeralRunner.Spec.GitHubServerTLS = &v1alpha1.GitHubServerTLSConfig{ | ||||
| 			ephemeralRunner.Spec.GitHubServerTLS = &v1alpha1.TLSConfig{ | ||||
| 				CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 						LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  |  | |||
|  | @ -1460,7 +1460,7 @@ var _ = Describe("Test EphemeralRunnerSet controller with custom root CA", func( | |||
| 				EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{ | ||||
| 					GitHubConfigUrl:    server.ConfigURLForOrg("my-org"), | ||||
| 					GitHubConfigSecret: configSecret.Name, | ||||
| 					GitHubServerTLS: &v1alpha1.GitHubServerTLSConfig{ | ||||
| 					GitHubServerTLS: &v1alpha1.TLSConfig{ | ||||
| 						CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 							ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||||
| 								LocalObjectReference: corev1.LocalObjectReference{ | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ import ( | |||
| 	"github.com/actions/actions-runner-controller/github/actions" | ||||
| 	"github.com/actions/actions-runner-controller/hash" | ||||
| 	"github.com/actions/actions-runner-controller/logging" | ||||
| 	"github.com/actions/actions-runner-controller/vault" | ||||
| 	"github.com/actions/actions-runner-controller/vault/azurekeyvault" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	rbacv1 "k8s.io/api/rbac/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
|  | @ -110,10 +110,6 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1. | |||
| 		annotationKeyValuesHash:     autoscalingRunnerSet.Annotations[annotationKeyValuesHash], | ||||
| 	} | ||||
| 
 | ||||
| 	if v, ok := autoscalingRunnerSet.Annotations[AnnotationKeyGitHubVaultType]; ok { | ||||
| 		annotations[AnnotationKeyGitHubVaultType] = v | ||||
| 	} | ||||
| 
 | ||||
| 	if err := applyGitHubURLLabels(autoscalingRunnerSet.Spec.GitHubConfigUrl, labels); err != nil { | ||||
| 		return nil, fmt.Errorf("failed to apply GitHub URL labels: %v", err) | ||||
| 	} | ||||
|  | @ -128,6 +124,7 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1. | |||
| 		Spec: v1alpha1.AutoscalingListenerSpec{ | ||||
| 			GitHubConfigUrl:               autoscalingRunnerSet.Spec.GitHubConfigUrl, | ||||
| 			GitHubConfigSecret:            autoscalingRunnerSet.Spec.GitHubConfigSecret, | ||||
| 			VaultConfig:                   autoscalingRunnerSet.VaultConfig(), | ||||
| 			RunnerScaleSetId:              runnerScaleSetId, | ||||
| 			AutoscalingRunnerSetNamespace: autoscalingRunnerSet.Namespace, | ||||
| 			AutoscalingRunnerSetName:      autoscalingRunnerSet.Name, | ||||
|  | @ -193,15 +190,18 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha | |||
| 		Metrics:                     autoscalingListener.Spec.Metrics, | ||||
| 	} | ||||
| 
 | ||||
| 	if ty, ok := autoscalingListener.Annotations[AnnotationKeyGitHubVaultType]; !ok { | ||||
| 	vault := autoscalingListener.Spec.VaultConfig | ||||
| 	if vault == nil { | ||||
| 		config.AppConfig = appConfig | ||||
| 	} else { | ||||
| 		vaultType := vault.VaultType(ty) | ||||
| 		if err := vaultType.Validate(); err != nil { | ||||
| 			return nil, fmt.Errorf("vault type validation error: %w", err) | ||||
| 		} | ||||
| 		config.VaultType = vaultType | ||||
| 		config.VaultType = vault.Type | ||||
| 		config.VaultLookupKey = autoscalingListener.Spec.GitHubConfigSecret | ||||
| 		config.AzureKeyVaultConfig = &azurekeyvault.Config{ | ||||
| 			TenantID:        vault.AzureKeyVault.TenantID, | ||||
| 			ClientID:        vault.AzureKeyVault.ClientID, | ||||
| 			URL:             vault.AzureKeyVault.URL, | ||||
| 			CertificatePath: vault.AzureKeyVault.CertificatePath, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if err := config.Validate(); err != nil { | ||||
|  | @ -520,10 +520,6 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A | |||
| 		annotationKeyRunnerSpecHash:           runnerSpecHash, | ||||
| 	} | ||||
| 
 | ||||
| 	if v, ok := autoscalingRunnerSet.Annotations[AnnotationKeyGitHubVaultType]; ok { | ||||
| 		newAnnotations[AnnotationKeyGitHubVaultType] = v | ||||
| 	} | ||||
| 
 | ||||
| 	newEphemeralRunnerSet := &v1alpha1.EphemeralRunnerSet{ | ||||
| 		TypeMeta: metav1.TypeMeta{}, | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
|  | @ -551,6 +547,7 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A | |||
| 				Proxy:              autoscalingRunnerSet.Spec.Proxy, | ||||
| 				GitHubServerTLS:    autoscalingRunnerSet.Spec.GitHubServerTLS, | ||||
| 				PodTemplateSpec:    autoscalingRunnerSet.Spec.Template, | ||||
| 				VaultConfig:        autoscalingRunnerSet.VaultConfig(), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ import ( | |||
| 	"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1/appconfig" | ||||
| 	"github.com/actions/actions-runner-controller/github/actions" | ||||
| 	"github.com/actions/actions-runner-controller/vault" | ||||
| 	"github.com/actions/actions-runner-controller/vault/azurekeyvault" | ||||
| 	"golang.org/x/net/http/httpproxy" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
|  | @ -19,28 +20,20 @@ import ( | |||
| ) | ||||
| 
 | ||||
| type SecretResolver struct { | ||||
| 	k8sClient      client.Client | ||||
| 	vaultResolvers map[vault.VaultType]resolver | ||||
| 	multiClient    actions.MultiClient | ||||
| 	k8sClient   client.Client | ||||
| 	multiClient actions.MultiClient | ||||
| } | ||||
| 
 | ||||
| type SecretResolverOption func(*SecretResolver) | ||||
| 
 | ||||
| func WithVault(ty vault.VaultType, vault vault.Vault) SecretResolverOption { | ||||
| 	return func(pool *SecretResolver) { | ||||
| 		pool.vaultResolvers[ty] = &vaultResolver{vault} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func NewSecretResolver(k8sClient client.Client, multiClient actions.MultiClient, opts ...SecretResolverOption) *SecretResolver { | ||||
| 	if k8sClient == nil { | ||||
| 		panic("k8sClient must not be nil") | ||||
| 	} | ||||
| 
 | ||||
| 	secretResolver := &SecretResolver{ | ||||
| 		k8sClient:      k8sClient, | ||||
| 		multiClient:    multiClient, | ||||
| 		vaultResolvers: make(map[vault.VaultType]resolver), | ||||
| 		k8sClient:   k8sClient, | ||||
| 		multiClient: multiClient, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, opt := range opts { | ||||
|  | @ -55,7 +48,8 @@ type ActionsGitHubObject interface { | |||
| 	GitHubConfigUrl() string | ||||
| 	GitHubConfigSecret() string | ||||
| 	Proxy() *v1alpha1.ProxyConfig | ||||
| 	GitHubServerTLS() *v1alpha1.GitHubServerTLSConfig | ||||
| 	GitHubServerTLS() *v1alpha1.TLSConfig | ||||
| 	VaultConfig() *v1alpha1.VaultConfig | ||||
| } | ||||
| 
 | ||||
| func (sr *SecretResolver) GetAppConfig(ctx context.Context, obj ActionsGitHubObject) (*appconfig.AppConfig, error) { | ||||
|  | @ -163,25 +157,32 @@ func (sr *SecretResolver) GetActionsService(ctx context.Context, obj ActionsGitH | |||
| } | ||||
| 
 | ||||
| func (sr *SecretResolver) resolverForObject(obj ActionsGitHubObject) (resolver, error) { | ||||
| 	ty, ok := obj.GetAnnotations()[AnnotationKeyGitHubVaultType] | ||||
| 	if !ok { | ||||
| 	vaultConfig := obj.VaultConfig() | ||||
| 	if vaultConfig == nil || vaultConfig.Type == "" { | ||||
| 		return &k8sResolver{ | ||||
| 			namespace: obj.GetNamespace(), | ||||
| 			client:    sr.k8sClient, | ||||
| 		}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	vaultType := vault.VaultType(ty) | ||||
| 	if err := vaultType.Validate(); err != nil { | ||||
| 		return nil, fmt.Errorf("invalid vault type %q: %v", ty, err) | ||||
| 	} | ||||
| 	switch vaultConfig.Type { | ||||
| 	case vault.VaultTypeAzureKeyVault: | ||||
| 		akv, err := azurekeyvault.New(azurekeyvault.Config{ | ||||
| 			TenantID:        vaultConfig.AzureKeyVault.TenantID, | ||||
| 			ClientID:        vaultConfig.AzureKeyVault.ClientID, | ||||
| 			URL:             vaultConfig.AzureKeyVault.URL, | ||||
| 			CertificatePath: vaultConfig.AzureKeyVault.CertificatePath, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to create Azure Key Vault client: %v", err) | ||||
| 		} | ||||
| 		return &vaultResolver{ | ||||
| 			vault: akv, | ||||
| 		}, nil | ||||
| 
 | ||||
| 	vault, ok := sr.vaultResolvers[vaultType] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("unknown vault resolver %q", ty) | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unknown vault type %q", vaultConfig.Type) | ||||
| 	} | ||||
| 
 | ||||
| 	return vault, nil | ||||
| } | ||||
| 
 | ||||
| type resolver interface { | ||||
|  |  | |||
							
								
								
									
										13
									
								
								main.go
								
								
								
								
							
							
						
						
									
										13
									
								
								main.go
								
								
								
								
							|  | @ -32,7 +32,6 @@ import ( | |||
| 	"github.com/actions/actions-runner-controller/github" | ||||
| 	"github.com/actions/actions-runner-controller/github/actions" | ||||
| 	"github.com/actions/actions-runner-controller/logging" | ||||
| 	"github.com/actions/actions-runner-controller/vault" | ||||
| 	"github.com/kelseyhightower/envconfig" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
|  | @ -275,21 +274,9 @@ func main() { | |||
| 			log.WithName("actions-clients"), | ||||
| 		) | ||||
| 
 | ||||
| 		vaults, err := vault.InitAll("CONTROLLER_MANAGER_") | ||||
| 		if err != nil { | ||||
| 			log.Error(err, "unable to read vaults") | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 
 | ||||
| 		var secretResolverOptions []actionsgithubcom.SecretResolverOption | ||||
| 		for name, vault := range vaults { | ||||
| 			secretResolverOptions = append(secretResolverOptions, actionsgithubcom.WithVault(name, vault)) | ||||
| 		} | ||||
| 
 | ||||
| 		secretResolver := actionsgithubcom.NewSecretResolver( | ||||
| 			mgr.GetClient(), | ||||
| 			actionsMultiClient, | ||||
| 			secretResolverOptions..., | ||||
| 		) | ||||
| 
 | ||||
| 		rb := actionsgithubcom.ResourceBuilder{ | ||||
|  |  | |||
|  | @ -3,10 +3,8 @@ package azurekeyvault | |||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets" | ||||
| 	"github.com/actions/actions-runner-controller/proxyconfig" | ||||
| ) | ||||
| 
 | ||||
| // AzureKeyVault is a struct that holds the Azure Key Vault client.
 | ||||
|  | @ -27,31 +25,6 @@ func New(cfg Config) (*AzureKeyVault, error) { | |||
| 	return &AzureKeyVault{client: client}, nil | ||||
| } | ||||
| 
 | ||||
| // FromEnv creates a new AzureKeyVault instance from environment variables.
 | ||||
| // The environment variables should be prefixed with the provided prefix.
 | ||||
| // For example, if the prefix is "AZURE_KEY_VAULT_", the environment variables should be:
 | ||||
| // AZURE_KEY_VAULT_TENANT_ID, AZURE_KEY_VAULT_CLIENT_ID, AZURE_KEY_VAULT_URL,
 | ||||
| // AZURE_KEY_VAULT_CERT_PATH, AZURE_KEY_VAULT_CERT_PASSWORD.
 | ||||
| // The proxy configuration can be set using the environment variables prefixed with "PROXY_".
 | ||||
| // For example, AZURE_KEY_VAULT_PROXY_HTTP_URL, AZURE_KEY_VAULT_PROXY_HTTP_USERNAME, etc.
 | ||||
| func FromEnv(prefix string) (*AzureKeyVault, error) { | ||||
| 	cfg := Config{ | ||||
| 		TenantID:     os.Getenv(prefix + "TENANT_ID"), | ||||
| 		ClientID:     os.Getenv(prefix + "CLIENT_ID"), | ||||
| 		URL:          os.Getenv(prefix + "URL"), | ||||
| 		CertPath:     os.Getenv(prefix + "CERT_PATH"), | ||||
| 		CertPassword: os.Getenv(prefix + "CERT_PASSWORD"), | ||||
| 	} | ||||
| 
 | ||||
| 	proxyConfig, err := proxyconfig.ReadFromEnv(prefix + "PROXY_") | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to read proxy config: %v", err) | ||||
| 	} | ||||
| 	cfg.Proxy = proxyConfig | ||||
| 
 | ||||
| 	return New(cfg) | ||||
| } | ||||
| 
 | ||||
| // GetSecret retrieves a secret from Azure Key Vault.
 | ||||
| func (v *AzureKeyVault) GetSecret(ctx context.Context, name string) (string, error) { | ||||
| 	secret, err := v.client.GetSecret(ctx, name, "", nil) | ||||
|  |  | |||
|  | @ -17,12 +17,11 @@ import ( | |||
| 
 | ||||
| // AzureKeyVault is a struct that holds the Azure Key Vault client.
 | ||||
| type Config struct { | ||||
| 	TenantID     string                   `json:"tenant_id"` | ||||
| 	ClientID     string                   `json:"client_id"` | ||||
| 	URL          string                   `json:"url"` | ||||
| 	CertPath     string                   `json:"cert_path"` | ||||
| 	CertPassword string                   `json:"cert_password"` // optional
 | ||||
| 	Proxy        *proxyconfig.ProxyConfig `json:"proxy,omitempty"` | ||||
| 	TenantID        string                   `json:"tenant_id"` | ||||
| 	ClientID        string                   `json:"client_id"` | ||||
| 	URL             string                   `json:"url"` | ||||
| 	CertificatePath string                   `json:"certificate_path"` | ||||
| 	Proxy           *proxyconfig.ProxyConfig `json:"proxy,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (c *Config) Validate() error { | ||||
|  | @ -36,12 +35,12 @@ func (c *Config) Validate() error { | |||
| 		return fmt.Errorf("failed to parse url: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if c.CertPath == "" { | ||||
| 	if c.CertificatePath == "" { | ||||
| 		return errors.New("cert path must be provided") | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := os.Stat(c.CertPath); err != nil { | ||||
| 		return fmt.Errorf("cert path %q does not exist: %v", c.CertPath, err) | ||||
| 	if _, err := os.Stat(c.CertificatePath); err != nil { | ||||
| 		return fmt.Errorf("cert path %q does not exist: %v", c.CertificatePath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := c.Proxy.Validate(); err != nil { | ||||
|  | @ -57,12 +56,12 @@ func (c *Config) Client() (*azsecrets.Client, error) { | |||
| } | ||||
| 
 | ||||
| func (c *Config) certClient() (*azsecrets.Client, error) { | ||||
| 	data, err := os.ReadFile(c.CertPath) | ||||
| 	data, err := os.ReadFile(c.CertificatePath) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to read cert file from path %q: %v", c.CertPath, err) | ||||
| 		return nil, fmt.Errorf("failed to read cert file from path %q: %v", c.CertificatePath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	certs, key, err := azidentity.ParseCertificates(data, []byte(c.CertPassword)) | ||||
| 	certs, key, err := azidentity.ParseCertificates(data, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to parse certificates: %w", err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -43,43 +43,38 @@ func TestConfigValidate_invalid(t *testing.T) { | |||
| 	tt := map[string]*Config{ | ||||
| 		"empty": {}, | ||||
| 		"no tenant id": { | ||||
| 			TenantID:     "", | ||||
| 			ClientID:     clientID, | ||||
| 			URL:          url, | ||||
| 			CertPath:     certPath, | ||||
| 			CertPassword: "", | ||||
| 			Proxy:        proxy, | ||||
| 			TenantID:        "", | ||||
| 			ClientID:        clientID, | ||||
| 			URL:             url, | ||||
| 			CertificatePath: certPath, | ||||
| 			Proxy:           proxy, | ||||
| 		}, | ||||
| 		"no client id": { | ||||
| 			TenantID:     tenantID, | ||||
| 			ClientID:     "", | ||||
| 			URL:          url, | ||||
| 			CertPath:     certPath, | ||||
| 			CertPassword: "", | ||||
| 			Proxy:        proxy, | ||||
| 			TenantID:        tenantID, | ||||
| 			ClientID:        "", | ||||
| 			URL:             url, | ||||
| 			CertificatePath: certPath, | ||||
| 			Proxy:           proxy, | ||||
| 		}, | ||||
| 		"no url": { | ||||
| 			TenantID:     tenantID, | ||||
| 			ClientID:     clientID, | ||||
| 			URL:          "", | ||||
| 			CertPath:     certPath, | ||||
| 			CertPassword: "", | ||||
| 			Proxy:        proxy, | ||||
| 			TenantID:        tenantID, | ||||
| 			ClientID:        clientID, | ||||
| 			URL:             "", | ||||
| 			CertificatePath: certPath, | ||||
| 			Proxy:           proxy, | ||||
| 		}, | ||||
| 		"no jwt and no cert path": { | ||||
| 			TenantID:     tenantID, | ||||
| 			ClientID:     clientID, | ||||
| 			URL:          url, | ||||
| 			CertPath:     "", | ||||
| 			CertPassword: "", | ||||
| 			Proxy:        proxy, | ||||
| 			TenantID:        tenantID, | ||||
| 			ClientID:        clientID, | ||||
| 			URL:             url, | ||||
| 			CertificatePath: "", | ||||
| 			Proxy:           proxy, | ||||
| 		}, | ||||
| 		"invalid proxy": { | ||||
| 			TenantID:     tenantID, | ||||
| 			ClientID:     clientID, | ||||
| 			URL:          url, | ||||
| 			CertPath:     certPath, | ||||
| 			CertPassword: "", | ||||
| 			TenantID:        tenantID, | ||||
| 			ClientID:        clientID, | ||||
| 			URL:             url, | ||||
| 			CertificatePath: certPath, | ||||
| 			Proxy: &proxyconfig.ProxyConfig{ | ||||
| 				HTTP: &proxyconfig.ProxyServerConfig{}, | ||||
| 			}, | ||||
|  | @ -120,19 +115,17 @@ func TestValidate_valid(t *testing.T) { | |||
| 
 | ||||
| 	tt := map[string]*Config{ | ||||
| 		"with cert": { | ||||
| 			TenantID:     tenantID, | ||||
| 			ClientID:     clientID, | ||||
| 			URL:          url, | ||||
| 			CertPath:     certPath, | ||||
| 			CertPassword: "", | ||||
| 			Proxy:        proxy, | ||||
| 			TenantID:        tenantID, | ||||
| 			ClientID:        clientID, | ||||
| 			URL:             url, | ||||
| 			CertificatePath: certPath, | ||||
| 			Proxy:           proxy, | ||||
| 		}, | ||||
| 		"without proxy": { | ||||
| 			TenantID:     tenantID, | ||||
| 			ClientID:     clientID, | ||||
| 			URL:          url, | ||||
| 			CertPath:     certPath, | ||||
| 			CertPassword: "", | ||||
| 			TenantID:        tenantID, | ||||
| 			ClientID:        clientID, | ||||
| 			URL:             url, | ||||
| 			CertificatePath: certPath, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,8 +3,6 @@ package vault | |||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/actions/actions-runner-controller/vault/azurekeyvault" | ||||
| ) | ||||
|  | @ -38,29 +36,3 @@ func (t VaultType) Validate() error { | |||
| 
 | ||||
| // Compile-time checks
 | ||||
| var _ Vault = (*azurekeyvault.AzureKeyVault)(nil) | ||||
| 
 | ||||
| // InitAll initializes all vaults based on the environment variables
 | ||||
| // that start with the given prefix. It returns a map of vault types to their
 | ||||
| // corresponding vault instances.
 | ||||
| //
 | ||||
| // Prefix is the namespace prefix used to filter environment variables.
 | ||||
| // For example, the listener environment variable are prefixed with "LISTENER_", followed by the vault type, followed by the value.
 | ||||
| //
 | ||||
| // For example, listener has prefix "LISTENER_", has "AZURE_KEY_VAULT_" configured,
 | ||||
| // and should read the vault URL. The environment variable will be "LISTENER_AZURE_KEY_VAULT_URL".
 | ||||
| func InitAll(prefix string) (map[VaultType]Vault, error) { | ||||
| 	envs := os.Environ() | ||||
| 
 | ||||
| 	result := make(map[VaultType]Vault) | ||||
| 	for _, env := range envs { | ||||
| 		if strings.HasPrefix(env, prefix+"AZURE_KEY_VAULT_") { | ||||
| 			akv, err := azurekeyvault.FromEnv(prefix + "AZURE_KEY_VAULT_") | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("failed to instantiate azure key vault from env: %v", err) | ||||
| 			} | ||||
| 			result[VaultTypeAzureKeyVault] = akv | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return result, nil | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue