diff --git a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go index c58e3854..987cccba 100644 --- a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go @@ -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 } diff --git a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go index 1d00abe0..534d3ab0 100644 --- a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go @@ -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{ diff --git a/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go b/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go index 38067b34..41b99ef7 100644 --- a/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go +++ b/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go @@ -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"` } diff --git a/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go b/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go index 1b7e218e..da2a9f02 100644 --- a/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go +++ b/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go @@ -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 { diff --git a/apis/actions.github.com/v1alpha1/tls_config_test.go b/apis/actions.github.com/v1alpha1/tls_config_test.go index c3a74bf7..e05bf81b 100644 --- a/apis/actions.github.com/v1alpha1/tls_config_test.go +++ b/apis/actions.github.com/v1alpha1/tls_config_test.go @@ -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{ diff --git a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go index b0947659..bebfed51 100644 --- a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go +++ b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go @@ -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 +} diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml index 7af045bd..6b894061 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml @@ -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 diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml index bf6f60cc..c6584d51 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml @@ -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 diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml index f7cf1139..b45d9ae8 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml @@ -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 diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml index 09d89ce7..3a1a4733 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml @@ -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 diff --git a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml index 4bae4b3b..18433580 100644 --- a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml +++ b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml @@ -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 }} diff --git a/charts/gha-runner-scale-set/tests/template_test.go b/charts/gha-runner-scale-set/tests/template_test.go index 050bded2..c08f9d3e 100644 --- a/charts/gha-runner-scale-set/tests/template_test.go +++ b/charts/gha-runner-scale-set/tests/template_test.go @@ -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{ diff --git a/charts/gha-runner-scale-set/values.yaml b/charts/gha-runner-scale-set/values.yaml index 776a3387..ba37980a 100644 --- a/charts/gha-runner-scale-set/values.yaml +++ b/charts/gha-runner-scale-set/values.yaml @@ -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. diff --git a/cmd/ghalistener/config/config.go b/cmd/ghalistener/config/config.go index 41bdcbee..e76b9dc8 100644 --- a/cmd/ghalistener/config/config.go +++ b/cmd/ghalistener/config/config.go @@ -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) diff --git a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml index 7af045bd..6b894061 100644 --- a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml +++ b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml @@ -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 diff --git a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml index bf6f60cc..c6584d51 100644 --- a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml +++ b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml @@ -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 diff --git a/config/crd/bases/actions.github.com_ephemeralrunners.yaml b/config/crd/bases/actions.github.com_ephemeralrunners.yaml index f7cf1139..b45d9ae8 100644 --- a/config/crd/bases/actions.github.com_ephemeralrunners.yaml +++ b/config/crd/bases/actions.github.com_ephemeralrunners.yaml @@ -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 diff --git a/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml b/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml index 09d89ce7..3a1a4733 100644 --- a/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml +++ b/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml @@ -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 diff --git a/controllers/actions.github.com/autoscalinglistener_controller_test.go b/controllers/actions.github.com/autoscalinglistener_controller_test.go index 330214c1..006d98de 100644 --- a/controllers/actions.github.com/autoscalinglistener_controller_test.go +++ b/controllers/actions.github.com/autoscalinglistener_controller_test.go @@ -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{ diff --git a/controllers/actions.github.com/autoscalingrunnerset_controller_test.go b/controllers/actions.github.com/autoscalingrunnerset_controller_test.go index 1bcae3fc..7411b6b9 100644 --- a/controllers/actions.github.com/autoscalingrunnerset_controller_test.go +++ b/controllers/actions.github.com/autoscalingrunnerset_controller_test.go @@ -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{ diff --git a/controllers/actions.github.com/constants.go b/controllers/actions.github.com/constants.go index 1a620906..cbf3309c 100644 --- a/controllers/actions.github.com/constants.go +++ b/controllers/actions.github.com/constants.go @@ -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 diff --git a/controllers/actions.github.com/ephemeralrunner_controller_test.go b/controllers/actions.github.com/ephemeralrunner_controller_test.go index a2563e0f..26d66814 100644 --- a/controllers/actions.github.com/ephemeralrunner_controller_test.go +++ b/controllers/actions.github.com/ephemeralrunner_controller_test.go @@ -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{ diff --git a/controllers/actions.github.com/ephemeralrunnerset_controller_test.go b/controllers/actions.github.com/ephemeralrunnerset_controller_test.go index 50fac910..a23d537a 100644 --- a/controllers/actions.github.com/ephemeralrunnerset_controller_test.go +++ b/controllers/actions.github.com/ephemeralrunnerset_controller_test.go @@ -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{ diff --git a/controllers/actions.github.com/resourcebuilder.go b/controllers/actions.github.com/resourcebuilder.go index 5a787e73..abdb0706 100644 --- a/controllers/actions.github.com/resourcebuilder.go +++ b/controllers/actions.github.com/resourcebuilder.go @@ -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(), }, }, } diff --git a/controllers/actions.github.com/secret_resolver.go b/controllers/actions.github.com/secret_resolver.go index 7e3fafff..88c4851c 100644 --- a/controllers/actions.github.com/secret_resolver.go +++ b/controllers/actions.github.com/secret_resolver.go @@ -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 { diff --git a/main.go b/main.go index dddb6d27..8f0025f9 100644 --- a/main.go +++ b/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{ diff --git a/vault/azurekeyvault/azurekeyvault.go b/vault/azurekeyvault/azurekeyvault.go index ee162950..1ec06403 100644 --- a/vault/azurekeyvault/azurekeyvault.go +++ b/vault/azurekeyvault/azurekeyvault.go @@ -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) diff --git a/vault/azurekeyvault/config.go b/vault/azurekeyvault/config.go index a7349b42..68eb7adb 100644 --- a/vault/azurekeyvault/config.go +++ b/vault/azurekeyvault/config.go @@ -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) } diff --git a/vault/azurekeyvault/config_test.go b/vault/azurekeyvault/config_test.go index b24835fb..2b3166c3 100644 --- a/vault/azurekeyvault/config_test.go +++ b/vault/azurekeyvault/config_test.go @@ -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, }, } diff --git a/vault/vault.go b/vault/vault.go index 6042c42f..6880a93d 100644 --- a/vault/vault.go +++ b/vault/vault.go @@ -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 -}