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