Skip to content
4 changes: 3 additions & 1 deletion backend/cmd/headlamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,9 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler {

// In-cluster
if config.UseInCluster {
context, err := kubeconfig.GetInClusterContext(config.oidcIdpIssuerURL,
context, err := kubeconfig.GetInClusterContext(
config.InClusterContextName,
config.oidcIdpIssuerURL,
config.oidcClientID, config.oidcClientSecret,
strings.Join(config.oidcScopes, ","),
config.oidcSkipTLSVerify,
Expand Down
1 change: 1 addition & 0 deletions backend/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func main() {
func buildHeadlampCFG(conf *config.Config, kubeConfigStore kubeconfig.ContextStore) *headlampconfig.HeadlampCFG {
return &headlampconfig.HeadlampCFG{
UseInCluster: conf.InCluster,
InClusterContextName: conf.InClusterContextName,
KubeConfigPath: conf.KubeConfigPath,
SkippedKubeContexts: conf.SkippedKubeContexts,
ListenAddr: conf.ListenAddr,
Expand Down
10 changes: 6 additions & 4 deletions backend/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ const (
)

type Config struct {
Version bool `koanf:"version"`
InCluster bool `koanf:"in-cluster"`
DevMode bool `koanf:"dev"`
InsecureSsl bool `koanf:"insecure-ssl"`
Version bool `koanf:"version"`
InCluster bool `koanf:"in-cluster"`
InClusterContextName string `koanf:"in-cluster-context-name"`
DevMode bool `koanf:"dev"`
InsecureSsl bool `koanf:"insecure-ssl"`
// NoBrowser disables automatically opening the default browser when running
// a locally embedded Headlamp binary (non in-cluster with spa.UseEmbeddedFiles == true).
// It has no effect in in-cluster mode or when running without embedded frontend.
Expand Down Expand Up @@ -412,6 +413,7 @@ func flagset() *flag.FlagSet {
func addGeneralFlags(f *flag.FlagSet) {
f.Bool("version", false, "Print version information and exit")
f.Bool("in-cluster", false, "Set when running from a k8s cluster")
f.String("in-cluster-context-name", "main", "Name to use for the in-cluster Kubernetes context")
f.Bool("dev", false, "Allow connections from other origins")
f.Bool("cache-enabled", false, "K8s cache in backend")
f.Bool("no-browser", false, "Disable automatically opening the browser when using embedded frontend")
Expand Down
17 changes: 17 additions & 0 deletions backend/pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ var ParseWithEnvTests = []struct {
assert.Equal(t, "~/.kube/test_config.yaml", conf.KubeConfigPath)
},
},
{
name: "in_cluster_context_name_env",
args: []string{"go run ./cmd"},
env: map[string]string{
"HEADLAMP_CONFIG_IN_CLUSTER_CONTEXT_NAME": "mycluster",
},
verify: func(t *testing.T, conf *config.Config) {
assert.Equal(t, "mycluster", conf.InClusterContextName)
},
},
}

func TestParseWithEnv(t *testing.T) {
Expand Down Expand Up @@ -215,6 +225,13 @@ func TestParseFlags(t *testing.T) {
assert.Equal(t, true, conf.EnableHelm)
},
},
{
name: "in_cluster_context_name_flag",
args: []string{"go run ./cmd", "--in-cluster-context-name=mycluster"},
verify: func(t *testing.T, conf *config.Config) {
assert.Equal(t, "mycluster", conf.InClusterContextName)
},
},
}

for _, tt := range tests {
Expand Down
1 change: 1 addition & 0 deletions backend/pkg/headlampconfig/headlampConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

type HeadlampCFG struct {
UseInCluster bool
InClusterContextName string
ListenAddr string
CacheEnabled bool
DevMode bool
Expand Down
19 changes: 13 additions & 6 deletions backend/pkg/kubeconfig/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ func buildUserAgent() string {
return fmt.Sprintf("%s %s (%s/%s)", AppName, Version, runtime.GOOS, runtime.GOARCH)
}

// TODO: Use a different way to avoid name clashes with other clusters.
const InClusterContextName = "main"
// DefaultInClusterContextName is the default name used for the in-cluster context.
const DefaultInClusterContextName = "main"

const (
KubeConfig = 1 << iota
Expand Down Expand Up @@ -1002,7 +1002,9 @@ func splitKubeConfigPath(path string) []string {
}

// GetInClusterContext returns the in-cluster context.
func GetInClusterContext(oidcIssuerURL string,
func GetInClusterContext(
contextName string,
oidcIssuerURL string,
oidcClientID string, oidcClientSecret string,
oidcScopes string,
oidcSkipTLSVerify bool,
Expand All @@ -1019,10 +1021,15 @@ func GetInClusterContext(oidcIssuerURL string,
CertificateAuthorityData: clusterConfig.CAData,
}

if strings.TrimSpace(contextName) == "" {
contextName = DefaultInClusterContextName
}

inClusterContext := &api.Context{
Cluster: InClusterContextName,
AuthInfo: InClusterContextName,
Cluster: contextName,
AuthInfo: contextName,
}
contextName = makeDNSFriendly(contextName)

inClusterAuthInfo := &api.AuthInfo{}

Expand All @@ -1041,7 +1048,7 @@ func GetInClusterContext(oidcIssuerURL string,
}

return &Context{
Name: InClusterContextName,
Name: contextName,
KubeContext: inClusterContext,
Cluster: cluster,
AuthInfo: inClusterAuthInfo,
Expand Down
3 changes: 3 additions & 0 deletions charts/headlamp/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ spec:
args:
{{- if .Values.config.inCluster }}
- "-in-cluster"
{{- if .Values.config.inClusterContextName }}
- "-in-cluster-context-name={{ .Values.config.inClusterContextName }}"
{{- end }}
{{- end }}
{{- with .Values.config.enableHelm }}
- "-enable-helm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ spec:
value: https://login.microsoftonline.com/tenant-id/v2.0
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
# Check if clientID is non empty either from env or oidc.config
Expand Down
1 change: 1 addition & 0 deletions charts/headlamp/tests/expected_templates/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ spec:
env:
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
ports:
Expand Down
1 change: 1 addition & 0 deletions charts/headlamp/tests/expected_templates/extra-args.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ spec:
env:
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
- -insecure-ssl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ spec:
env:
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
ports:
Expand Down
158 changes: 158 additions & 0 deletions charts/headlamp/tests/expected_templates/httproute-enabled.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
---
# Source: headlamp/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: headlamp
namespace: default
labels:
helm.sh/chart: headlamp-0.39.0
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
app.kubernetes.io/version: "0.39.0"
app.kubernetes.io/managed-by: Helm
---
# Source: headlamp/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: oidc
namespace: default
type: Opaque
data:
---
# Source: headlamp/templates/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: headlamp-admin
labels:
helm.sh/chart: headlamp-0.39.0
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
app.kubernetes.io/version: "0.39.0"
app.kubernetes.io/managed-by: Helm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: headlamp
namespace: default
---
# Source: headlamp/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: headlamp
namespace: default
labels:
helm.sh/chart: headlamp-0.39.0
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
app.kubernetes.io/version: "0.39.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP

ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
---
# Source: headlamp/templates/deployment.yaml
# This block of code is used to extract the values from the env.
# This is done to check if the values are non-empty and if they are, they are used in the deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
name: headlamp
namespace: default
labels:
helm.sh/chart: headlamp-0.39.0
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
app.kubernetes.io/version: "0.39.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
template:
metadata:
labels:
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
spec:
serviceAccountName: headlamp
automountServiceAccountToken: true
securityContext:
{}
containers:
- name: headlamp
securityContext:
privileged: false
runAsGroup: 101
runAsNonRoot: true
runAsUser: 100
image: "ghcr.io/headlamp-k8s/headlamp:v0.39.0"
imagePullPolicy: IfNotPresent

env:
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
ports:
- name: http
containerPort: 4466
protocol: TCP
livenessProbe:
httpGet:
path: "/"
port: http
readinessProbe:
httpGet:
path: "/"
port: http
resources:
{}
---
# Source: headlamp/templates/httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: headlamp
namespace: default
labels:
helm.sh/chart: headlamp-0.39.0
app.kubernetes.io/name: headlamp
app.kubernetes.io/instance: headlamp
app.kubernetes.io/version: "0.39.0"
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: ingress
annotations:
gateway.example.com/annotation: test
spec:
parentRefs:
- name: my-gateway
namespace: gateway-namespace
hostnames:
- headlamp.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: headlamp
port: 80
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ spec:
value: /oauth2/userinfocustom1
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
- "-me-user-info-url=$(ME_USER_INFO_URL)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ spec:
key: meUserInfoURL
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
- "-me-user-info-url=$(ME_USER_INFO_URL)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ spec:
key: scopes
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
# Check if clientID is non empty either from env or oidc.config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ spec:
env:
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
ports:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ spec:
value: openid email profile
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
# Check if clientID is non empty either from env or oidc.config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ spec:
key: scopes
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
# Check if clientID is non empty either from env or oidc.config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ spec:
value: testScope
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
# Check if clientID is non empty either from env or oidc.config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ spec:
value: testScope
args:
- "-in-cluster"
- "-in-cluster-context-name=main"
- "-plugins-dir=/headlamp/plugins"
# Check if externalSecret is disabled
# Check if clientID is non empty either from env or oidc.config
Expand Down
Loading
Loading