Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow ssh-credentials to be set in agent and plugin #248

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
10 changes: 8 additions & 2 deletions examples/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ org: my-buildkite-org
cluster-uuid: beefcafe-abbe-baba-abba-deedcedecade

tags:
- queue=my-queue
- priority=high
- queue=my-queue
- priority=high

# ssh-credentials-secret are the secret with the ssh credentials
# configured on the agent with docker-ssh-config
# @see https://github.com/buildkite/docker-ssh-env-config
ssh-credentials-secret: buildkite-ssh-github-creds


# This will be applied to the job's podSpec as a strategic merge patch
# See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch
Expand Down
2 changes: 2 additions & 0 deletions internal/controller/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Config struct {
ClusterUUID string `json:"cluster-uuid" validate:"omitempty"`
AdditionalRedactedVars stringSlice `json:"additional-redacted-vars" validate:"omitempty"`
PodSpecPatch *corev1.PodSpec `json:"pod-spec-patch" validate:"omitempty"`
SSHCredentialsSecret string `mapstructure:"ssh-credentials-secret" validate:"omitempty"`
}

type stringSlice []string
Expand All @@ -47,6 +48,7 @@ func (s stringSlice) MarshalLogArray(enc zapcore.ArrayEncoder) error {

func (c Config) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("agent-token-secret", c.AgentTokenSecret)
enc.AddString("ssh-credentials-secret", c.SSHCredentialsSecret)
enc.AddBool("debug", c.Debug)
enc.AddString("image", c.Image)
enc.AddDuration("job-ttl", c.JobTTL)
Expand Down
1 change: 1 addition & 0 deletions internal/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func Run(
JobTTL: cfg.JobTTL,
AdditionalRedactedVars: cfg.AdditionalRedactedVars,
PodSpecPatch: cfg.PodSpecPatch,
SSHCredentialsSecret: cfg.SSHCredentialsSecret,
})
limiter := scheduler.NewLimiter(logger.Named("limiter"), sched, cfg.MaxInFlight)

Expand Down
50 changes: 36 additions & 14 deletions internal/controller/scheduler/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Config struct {
JobTTL time.Duration
AdditionalRedactedVars []string
PodSpecPatch *corev1.PodSpec
SSHCredentialsSecret string
}

func New(logger *zap.Logger, client kubernetes.Interface, cfg Config) *worker {
Expand All @@ -49,13 +50,14 @@ func New(logger *zap.Logger, client kubernetes.Interface, cfg Config) *worker {
}

type KubernetesPlugin struct {
PodSpec *corev1.PodSpec `json:"podSpec,omitempty"`
PodSpecPatch *corev1.PodSpec `json:"podSpecPatch,omitempty"`
GitEnvFrom []corev1.EnvFromSource `json:"gitEnvFrom,omitempty"`
Sidecars []corev1.Container `json:"sidecars,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
ExtraVolumeMounts []corev1.VolumeMount `json:"extraVolumeMounts,omitempty"`
Checkout Checkout `json:"checkout,omitempty"`
PodSpec *corev1.PodSpec `json:"podSpec,omitempty"`
PodSpecPatch *corev1.PodSpec `json:"podSpecPatch,omitempty"`
SSHCredentialsSecret string
GitEnvFrom []corev1.EnvFromSource `json:"gitEnvFrom,omitempty"`
Sidecars []corev1.Container `json:"sidecars,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
ExtraVolumeMounts []corev1.VolumeMount `json:"extraVolumeMounts,omitempty"`
Checkout Checkout `json:"checkout,omitempty"`
}

type Checkout struct {
Expand Down Expand Up @@ -111,6 +113,7 @@ type jobWrapper struct {
logger *zap.Logger
job *api.CommandJob
envMap map[string]string
envFrom []corev1.EnvFromSource
err error
k8sPlugin KubernetesPlugin
otherPlugins []map[string]json.RawMessage
Expand All @@ -119,10 +122,11 @@ type jobWrapper struct {

func NewJobWrapper(logger *zap.Logger, job *api.CommandJob, config Config) *jobWrapper {
return &jobWrapper{
logger: logger,
job: job,
cfg: config,
envMap: make(map[string]string),
logger: logger,
job: job,
cfg: config,
envMap: make(map[string]string),
envFrom: make([]corev1.EnvFromSource, 0),
}
}

Expand Down Expand Up @@ -230,6 +234,24 @@ func (w *jobWrapper) Build(skipCheckout bool) (*batchv1.Job, error) {
Value: w.job.Uuid,
},
}

// Generate env from configuration for git credentials
secretName := w.cfg.SSHCredentialsSecret
if w.k8sPlugin.SSHCredentialsSecret != "" {
secretName = w.k8sPlugin.SSHCredentialsSecret
}

if secretName != "" && len(w.k8sPlugin.GitEnvFrom) == 0 {
w.envFrom = append(w.envFrom, corev1.EnvFromSource{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{Name: secretName},
},
})
} else if len(w.k8sPlugin.GitEnvFrom) > 0 {
w.logger.Warn("git-env-from is deprecated, please use ssh-credentials-secret instead")
w.envFrom = append(w.envFrom, w.k8sPlugin.GitEnvFrom...)
}

if w.otherPlugins != nil {
otherPluginsJson, err := json.Marshal(w.otherPlugins)
if err != nil {
Expand Down Expand Up @@ -332,7 +354,7 @@ func (w *jobWrapper) Build(skipCheckout bool) (*batchv1.Job, error) {
c.WorkingDir = "/workspace"
}
c.VolumeMounts = append(c.VolumeMounts, volumeMounts...)
c.EnvFrom = append(c.EnvFrom, w.k8sPlugin.GitEnvFrom...)
c.EnvFrom = append(c.EnvFrom, w.envFrom...)
podSpec.Containers[i] = c
}

Expand Down Expand Up @@ -366,7 +388,7 @@ func (w *jobWrapper) Build(skipCheckout bool) (*batchv1.Job, error) {
c.Name = fmt.Sprintf("%s-%d", "sidecar", i)
}
c.VolumeMounts = append(c.VolumeMounts, volumeMounts...)
c.EnvFrom = append(c.EnvFrom, w.k8sPlugin.GitEnvFrom...)
c.EnvFrom = append(c.EnvFrom, w.envFrom...)
podSpec.Containers = append(podSpec.Containers, c)
}

Expand Down Expand Up @@ -561,7 +583,7 @@ func (w *jobWrapper) createCheckoutContainer(
Value: w.k8sPlugin.Checkout.FetchFlags,
},
},
EnvFrom: w.k8sPlugin.GitEnvFrom,
EnvFrom: w.envFrom,
}
checkoutContainer.Env = append(checkoutContainer.Env, env...)

Expand Down
30 changes: 30 additions & 0 deletions internal/integration/fixtures/secretref.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ steps:
- echo
- hello world

- label: ":git::console::superhero: checkout private git with ssh credentials secret as root"
agents:
queue: {{.queue}}
plugins:
- kubernetes:
ssh-credentials-secret: agent-stack-k8s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ssh-credentials-secret: agent-stack-k8s
sshCredentialsSecret: agent-stack-k8s

podSpec:
containers:
- image: alpine:latest
command:
- echo
- hello world

- label: ":git::console::student: checkout private git repo as user"
agents:
queue: {{.queue}}
Expand All @@ -32,3 +45,20 @@ steps:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1001

- label: ":git::console::student: checkout private git with ssh credentials secret repo as user"
agents:
queue: {{.queue}}
plugins:
- kubernetes:
ssh-credentials-secret: agent-stack-k8s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ssh-credentials-secret: agent-stack-k8s
sshCredentialsSecret: agent-stack-k8s

podSpec:
containers:
- image: alpine:latest
command:
- echo
- hello world
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1001