helm

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 46 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// ESOChartName / ESOChartRepo / ESOChartVersion 은 공식 External Secrets
	// Operator 차트다. 컨트롤러·웹훅·cert-controller 를 코드 수정 없이 그대로
	// 사용하며, Nullus 가 작성하는 것은 SecretStore/ExternalSecret 뿐이다.
	ESOChartName    = "external-secrets"
	ESOChartRepo    = "https://charts.external-secrets.io"
	ESOChartVersion = "2.7.0"

	// ESONamespace 는 ESO 를 깔 클러스터 공용 네임스페이스다.
	//
	// 스택 네임스페이스에 깔면 그 네임스페이스를 지울 수 없게 된다. ESO 는 자기가
	// 만든 ExternalSecret 에 externalsecret-cleanup finalizer 를 붙이고 그것을 뗄 수
	// 있는 것은 ESO 컨트롤러뿐인데, `kubectl delete namespace` 는 파드와
	// ExternalSecret 을 병렬로 지운다 — 컨트롤러가 먼저 죽으면 finalizer 가 영구히
	// 남아 네임스페이스가 Terminating 에서 끝나지 않는다(2026-10-17 실측: 22분 뒤에도
	// 그대로였고 finalizer 를 손으로 비우니 즉시 끝났다).
	//
	// 공용 네임스페이스에 두면 컨트롤러가 스택 네임스페이스보다 오래 살아 finalizer 를
	// 스스로 뗀다. cert-manager(cert-manager)·metrics-server(kube-system) 가 같은
	// 이유로 자기 네임스페이스를 못박고 있다. ESO 의 CRD·검증 웹훅도 원래 클러스터에
	// 하나뿐이라 스택마다 깔 이유가 없었다.
	ESONamespace = "external-secrets"

	// ESOSecretStoreName 은 스택 네임스페이스에 만드는 SecretStore 이름이다.
	// 스택이 단일 네임스페이스에 설치되므로 ClusterSecretStore 는 쓰지 않는다.
	ESOSecretStoreName = "nullus-openbao"
)
View Source
const (

	// OpenBaoKVMount 는 KV v2 시크릿 엔진의 마운트 이름이다.
	//
	// 경로 규약(`kv/nullus/{env}/{org}/...`)과 실제 마운트를 일치시키기 위해
	// "secret" 이 아니라 "kv" 로 마운트한다. 운영 모드는 dev 모드와 달리
	// 엔진이 자동 마운트되지 않으므로 부트스트랩에서 명시적으로 활성화한다.
	OpenBaoKVMount = "kv"

	// OpenBao Kubernetes Auth role 이름
	OpenBaoControllerRole = "nullus-controller"
	OpenBaoESORole        = "nullus-eso"

	// role 에 바인딩되는 ServiceAccount 이름
	OpenBaoControllerServiceAccount = "nullus-controller"
	OpenBaoESOServiceAccount        = "external-secrets"
)
View Source
const (

	// OpenBaoKeyShares / OpenBaoKeyThreshold 기본값은 1/1 이다.
	// auto-unseal 구성에서는 threshold 를 채우는 데 필요한 모든 조각이
	// 어차피 같은 Secret 안에 있으므로, 분할이 런타임 보안을 높이지 않고
	// 복잡도만 늘린다. 오프라인 백업본을 여러 관리자에게 나누려는 조직만
	// 이 값을 올리면 된다.
	OpenBaoKeyShares    = 1
	OpenBaoKeyThreshold = 1
)
View Source
const (
	// OpenBaoImageRepository / OpenBaoImageTag 는 OpenBao 이미지를 고정한다.
	// 에어갭 번들은 재현 가능해야 하므로 latest 같은 mutable 태그를 쓰지 않는다.
	OpenBaoImageRepository = "openbao/openbao"
	OpenBaoImageTag        = "2.5.5"

	// OpenBaoKubectlImage 는 init Job 이 K8s Secret 을 만들 때 사용하는 이미지다.
	// OpenBao 이미지에는 kubectl 이 없어 별도 컨테이너가 필요하다.
	OpenBaoKubectlImage = shareddomain.KubectlImage

	// OpenBaoUnsealKeysSecret 은 init Job 이 만든 unseal key 와 root token 을 담는다.
	// 이 Secret 과 OpenBao PVC 는 생애주기를 함께한다 — 한쪽만 남으면 재설치 시
	// 금고를 열 수 없게 되므로 삭제도 항상 함께 수행한다.
	OpenBaoUnsealKeysSecret = "openbao-unseal-keys"

	// OpenBaoDataStorageSize 는 file 스토리지 백엔드용 PVC 크기다.
	OpenBaoDataStorageSize = "5Gi"
)
View Source
const (
	ProvisionedPostgresSecret      = domain.ProvisionedPostgresSecret
	ProvisionedMinIOSecret         = domain.ProvisionedMinIOSecret
	ProvisionedGitLabRootSecret    = domain.GitLabRootSecret
	ProvisionedObjectStorageSecret = domain.ProvisionedObjectStorageSecret

	// Container Registry 전용 스토리지 설정. Rails 의 object_store 와 형식이
	// 달라(Docker distribution 스키마) 같은 Secret 에 담을 수 없다.
	ProvisionedRegistryStorageSecret = domain.ProvisionedRegistryStorageSecret
	RegistryStorageSecretKey         = "config"
	RegistryStorageBucket            = "gitlab-registry"

	// MinIORootUser 는 비밀이 아니지만 차트의 existingSecret 이 같은 Secret 안에서
	// 요구하므로 함께 프로비저닝한다.
	MinIORootUser = domain.MinIORootUser
)

프로비저닝된 Secret 이름. 차트 values 가 existingSecret 으로 참조한다.

값의 단일 출처는 domain 이다 — 설치 경로와 조회 경로(연결정보 안내)가 같은 이름을 봐야 하는데, 양쪽에 각각 적어 두면 한쪽만 바뀌었을 때 조용히 어긋난다.

View Source
const ArgoCDSecretName = "argocd-secret" // #nosec G101 -- Secret 리소스 이름

ArgoCDSecretName 은 ArgoCD 가 읽는 Secret 이름이다. admin 해시와 OIDC client secret 이 한 Secret 에 공존하므로 ESO 가 단독 소유한다.

View Source
const GitLabOIDCSecretName = "gitlab-oidc-provider" // #nosec G101 -- Secret 리소스 이름

GitLabOIDCSecretName 은 GitLab 이 omniauth provider 로 읽는 Secret 이름이다.

GitLab 은 provider 설정을 client secret 하나가 아니라 "블록 전체" 로 받는다. 그래서 다른 도구처럼 client-secret 키만 담은 Secret 으로는 안 되고, ESO 의 target.template 으로 provider YAML 을 만들어 넣는다.

View Source
const JenkinsGiteaCredentialID = "nullus-gitea"

JenkinsGiteaCredentialID 는 Jenkins 에 등록되는 Gitea 자격증명 식별자다.

CI/CD 모듈의 job 설정이 같은 이름을 참조한다(cicd/usecase 의 giteaCredentialID). 모듈 간 직접 import 는 금지되므로 값을 각자 두되, 갈라지면 job 이 브랜치를 하나도 찾지 못하므로 계약 테스트로 묶는다.

Variables

View Source
var ErrRunnerTokenDiscovery = errors.New("gitlab runner 등록 토큰을 얻지 못했습니다")

ErrRunnerTokenDiscovery 는 Runner 등록 토큰을 얻지 못했음을 알리는 sentinel 이다.

과거에는 이 실패를 무시하고 스텝을 completed 로 마킹했다. 그러면 CI 실행기가 없는데도 스택이 completed 로 끝나 파이프라인이 한 건도 돌지 않는 상태가 조용히 만들어진다. 설치 실패로 드러내야 재시도 경로를 탈 수 있다.

Functions

func AirgapMode added in v0.6.0

func AirgapMode() bool

AirgapMode 는 플랫폼이 에어갭 모드로 설치하는지 본다.

차트를 내부 OCI 레지스트리에서 받는 설치가 곧 에어갭 설치다. 설치 이미지 스캔처럼 외부 레지스트리에 닿아야 하는 일은 이 값으로 끈다 — 판단 근거를 한 곳에 둔다.

func DefaultValues

func DefaultValues(stepName string) map[string]any

func SSOSecretName

func SSOSecretName(clientID string) string

SSOSecretName 은 client secret 이 복제될 Kubernetes Secret 이름이다.

func StepForRelease

func StepForRelease(releaseName string) string

StepForRelease 는 릴리스를 만든 설치 단계를 돌려준다.

이 값이 비면 편집한 values 를 어느 오버라이드 키로 저장할지 알 수 없고, 그러면 다음 재배포에서 사용자의 편집이 조용히 사라진다.

Types

type ArgoCDUpgradeHealthVerifier added in v0.6.0

type ArgoCDUpgradeHealthVerifier struct {
	// contains filtered or unexported fields
}

ArgoCDUpgradeHealthVerifier 는 Helm 이 성공이라 한 뒤 Argo CD 가 실제로 그 버전으로 살아 있는지 본다 — 모든 Deployment · StatefulSet 이 새 세대로 준비됐고, API 서버가 대상 이미지로 떠 있어야 한다. Secret 은 읽지 않는다.

func NewArgoCDUpgradeHealthVerifier added in v0.6.0

func NewArgoCDUpgradeHealthVerifier() *ArgoCDUpgradeHealthVerifier

func (*ArgoCDUpgradeHealthVerifier) Verify added in v0.6.0

func (v *ArgoCDUpgradeHealthVerifier) Verify(ctx context.Context, kubeconfig []byte, namespace string, bundle domain.UpgradeBundle) error

type ChartSpec

type ChartSpec struct {
	ReleaseName string
	ChartName   string
	RepoURL     string
	Version     string
	Namespace   string
	Values      map[string]any
	Wait        bool
}

func DefaultChartSpecForStep

func DefaultChartSpecForStep(step string) (ChartSpec, bool)

DefaultChartSpecForStep 은 단계의 기본 차트 스펙을 돌려준다.

설치가 실제로 어떤 차트를 쓰는지 다른 패키지에서 확인할 수 있도록 공개한다 — 화면에 안내하는 버전과 어긋나지 않는지 계약 테스트가 이 값을 본다.

type GatewayAddressReader added in v0.6.0

type GatewayAddressReader struct {
	// contains filtered or unexported fields
}

GatewayAddressReader 는 스택 게이트웨이 데이터 플레인 Service 의 ClusterIP 를 읽는다 (port.GatewayAddressReader). 설치가 hostAliases 에 박는 바로 그 주소다(loadGatewayClusterIP).

func NewGatewayAddressReader added in v0.6.0

func NewGatewayAddressReader(kubeconfig []byte) (*GatewayAddressReader, error)

NewGatewayAddressReader 는 대상 클러스터의 kubeconfig 로 만든다.

복구 직후에는 게이트웨이 Service 가 아직 없을 수 있다 — 덤프에 없으면 Envoy Gateway 컨트롤러가 다시 만든다. 그래서 잠시 기다린다.

func (*GatewayAddressReader) GatewayClusterIP added in v0.6.0

func (r *GatewayAddressReader) GatewayClusterIP(ctx context.Context, namespace string) (string, error)

GatewayClusterIP 는 네임스페이스의 게이트웨이 Service 주소다. 기다려도 없으면 오류다.

type HelmInstaller

type HelmInstaller struct {
	// contains filtered or unexported fields
}

func NewHelmInstaller

func NewHelmInstaller(kubeconfig []byte) *HelmInstaller

func (*HelmInstaller) GetValues

func (h *HelmInstaller) GetValues(ctx context.Context, releaseName, namespace string) (map[string]any, error)

func (*HelmInstaller) Install

func (*HelmInstaller) ListReleases

func (h *HelmInstaller) ListReleases(ctx context.Context, namespace string) ([]port.ReleaseInfo, error)

func (*HelmInstaller) RollbackRelease added in v0.6.0

func (h *HelmInstaller) RollbackRelease(_ context.Context, releaseName, namespace string, revision int) error

func (*HelmInstaller) Status

func (h *HelmInstaller) Status(ctx context.Context, releaseName, namespace string) (*port.HelmInstallResult, error)

func (*HelmInstaller) Uninstall

func (h *HelmInstaller) Uninstall(ctx context.Context, releaseName, namespace string) error

func (*HelmInstaller) Upgrade

func (*HelmInstaller) UpgradeChart added in v0.6.0

UpgradeChart is the version-changing path. It is separate from the values editor, whose contract deliberately reuses the currently installed chart.

type ManagedSecret

type ManagedSecret struct {
	TargetSecret    string
	Consumer        string
	RestartRequired bool
	Entries         []SecretEntry
	// TemplateData 가 있으면 ExternalSecret 의 target.template 으로 렌더링한다.
	// 값 안에서 {{ .키 }} 로 Entries 의 TargetKey 를 참조한다.
	TemplateData map[string]string
	// KeepEntries 는 템플릿과 함께 Entries 의 원본 값도 Secret 에 남긴다.
	// (externalsecret.Spec.KeepEntries)
	KeepEntries bool
}

ManagedSecret 은 ESO 가 소유하는 대상 Secret 하나를 기술한다.

RestartRequired 는 회전 후 반영 전략의 스펙이다. 소비 방식에 따라 재시작 필요 여부가 달라진다 — Runner 는 기동 시 config 를 1회만 읽지만 ArgoCD 의 repository Secret 은 매 요청 시점에 읽는다.

type Orchestrator

type Orchestrator struct {
	// contains filtered or unexported fields
}

func NewOrchestrator

func NewOrchestrator(installer port.HelmInstaller, kubeconfig []byte, namespace string, opts ...OrchestratorOption) *Orchestrator

func (*Orchestrator) ExecuteStep

func (o *Orchestrator) ExecuteStep(ctx context.Context, stackID, step, phase string) error

func (*Orchestrator) InstallExternalSecrets

func (o *Orchestrator) InstallExternalSecrets(ctx context.Context, namespace string) error

InstallExternalSecrets 는 ESO 설치 전 과정을 하나의 경로로 묶는다.

차트 설치 → 준비 대기 → SecretStore 적용까지 여기서 처리하므로, 오케스트레이터와 통합 테스트가 같은 코드를 통과한다. CRD 소유권 보정도 이 안에서 이뤄져 우회 경로가 생기지 않는다.

func (*Orchestrator) IsStepEnabled

func (o *Orchestrator) IsStepEnabled(step string) bool

func (*Orchestrator) PreflightArchitecture added in v0.6.0

func (o *Orchestrator) PreflightArchitecture(ctx context.Context, stackID string) ([]string, error)

PreflightArchitecture 는 설치를 시작하기 전에 노드 아키텍처를 읽고, 이번에 설치할 단계의 도구가 그 노드에서 뜰 이미지가 있는지 본다.

공식 이미지가 amd64 뿐인 Harbor 를 arm64 노드에 깔면 헬름은 성공하고 파드만 크래시한다. 그 실패는 설치가 한참 진행된 뒤에야 드러나므로 여기서 멈춘다. 대체 출처를 쓰게 되면 그 사실을 알림으로 돌려준다 — 공식이 아닌 이미지를 쓰는 것은 설치 로그에 남아야 한다.

이어서 진행하면 재개 지점 앞의 단계는 보지 않는다. 다시 설치하지 않는 도구 때문에 뒤 단계를 이어갈 수 없게 되면 안 된다.

노드를 읽지 못하면, 이미지가 노드 아키텍처에 달린 도구를 설치할 때만 멈춘다. 조용히 공식 이미지로 가면 arm64 에서 같은 실패가 재발한다.

func (*Orchestrator) PreflightNamespace

func (o *Orchestrator) PreflightNamespace(ctx context.Context, namespace string) error

PreflightNamespace 는 설치를 시작하기 전에 그 자리가 비어 있는지 본다.

이전 설치의 볼륨이 남아 있으면 새 설치가 옛 데이터베이스를 물려받는다. 그 안의 비밀번호는 이번에 새로 만든 Secret 과 다르고, 그 사실은 한참 뒤에 엉뚱한 도구의 오류로 드러난다 — PostgreSQL 은 Gitea 의 28P01 로, Harbor 는 프로비저닝 401 로 나왔다. 둘 다 20분을 태운 뒤였다.

여기서 멈추면 몇 초 만에 알 수 있다.

func (*Orchestrator) ProvisionSecrets

func (o *Orchestrator) ProvisionSecrets(
	ctx context.Context,
	namespace, env, orgID string,
	writer SecretWriter,
) error

ProvisionSecrets 는 시크릿을 생성해 OpenBao 에 기록하고 ExternalSecret 을 적용한 뒤, ESO 가 실제 Kubernetes Secret 을 만들 때까지 기다린다.

대기가 필수다. ExternalSecret 을 apply 해도 ESO 가 Secret 을 만들기까지 시간이 걸리고, 그 전에 후속 Helm 설치가 existingSecret 을 참조하면 파드가 기동에 실패한다.

이미 값이 있으면 보존한다. 재설치·스텝 재시도로 비밀번호가 바뀌면 기존 데이터에 접근할 수 없게 되기 때문이다.

func (*Orchestrator) ResumeFromStep

func (o *Orchestrator) ResumeFromStep(stackID, step string)

ResumeFromStep initializes ordering for a new executor created during a continued deployment, so the failed step can be reapplied directly.

func (*Orchestrator) RevokeOpenBaoRootToken

func (o *Orchestrator) RevokeOpenBaoRootToken(ctx context.Context, namespace string) error

RevokeOpenBaoRootToken 은 root token 을 폐기하고 Secret 에서도 제거한다.

Kubernetes Auth 가 실제로 동작한다는 것이 확인된 뒤에 호출해야 한다. 그 전에 폐기하면 인증 경로가 하나도 남지 않는다.

폐기해도 복구할 수 있다 — unseal key threshold 를 충족하면 `bao operator generate-root` 로 재발급할 수 있고, 키는 같은 클러스터의 openbao-unseal-keys Secret 에 있다.

func (*Orchestrator) RollbackDeployment

func (o *Orchestrator) RollbackDeployment(ctx context.Context, stackID string) error

func (*Orchestrator) SetNamespace

func (o *Orchestrator) SetNamespace(namespace string)

func (*Orchestrator) SetSSOProvisionerFactory

func (o *Orchestrator) SetSSOProvisionerFactory(factory port.SSOProvisionerFactory)

SetSSOProvisionerFactory 는 스택별 SSO provisioner 생성기를 주입한다.

func (*Orchestrator) SetSecretScope

func (o *Orchestrator) SetSecretScope(env, orgID string)

SetSecretScope 는 OpenBao 경로 접두사에 쓰이는 환경/조직을 설정한다. install_stack 이 스택 컨텍스트를 알고 있으므로 거기서 주입한다.

func (*Orchestrator) SetStackConfig

func (o *Orchestrator) SetStackConfig(config domain.StackConfig)

func (*Orchestrator) StartStepRuntimeTail

func (o *Orchestrator) StartStepRuntimeTail(ctx context.Context, stackID, step string, emit func(level, message string)) (stop func())

func (*Orchestrator) StepRuntimeLogs

func (o *Orchestrator) StepRuntimeLogs(ctx context.Context, stackID, step string) (infos []string, warns []string)

func (*Orchestrator) VerifyDeployment

func (o *Orchestrator) VerifyDeployment(ctx context.Context, stackID string) error

type OrchestratorOption

type OrchestratorOption func(*Orchestrator)

func WithImageProjectName

func WithImageProjectName(name string) OrchestratorOption

WithImageProjectName 은 레지스트리 프로젝트 이름을 주입한다.

CI/CD 모듈의 그룹 경로(NULLUS_SCM_GROUP)와 같은 값이어야 한다 — 다르면 프로젝트는 만들어지는데 CI 가 push 하는 주소는 다른 프로젝트를 가리켜 "project not found" 로 막힌다.

func WithResourceDefaultRepository

func WithResourceDefaultRepository(repo port.ResourceDefaultRepository) OrchestratorOption

func WithSharedClusterScopedComponents

func WithSharedClusterScopedComponents(enabled bool) OrchestratorOption

func WithToolOIDCIssuer

func WithToolOIDCIssuer(issuer string) OrchestratorOption

WithToolOIDCIssuer 는 설치되는 OSS 에 넣을 Keycloak issuer 를 주입한다.

포털이 로그인한 Keycloak 과 오리진이 같아야 SSO 세션 쿠키가 실려 도구로 재인증 없이 넘어간다. 그래서 이 값은 스택의 access_domain 이 아니라 플랫폼 설정에서 온다 — 플랫폼 Keycloak 은 스택마다가 아니라 하나뿐이기 때문이다.

type RollbackManager

type RollbackManager struct {
	// contains filtered or unexported fields
}

func (*RollbackManager) Push

func (rm *RollbackManager) Push(releaseName string)

func (*RollbackManager) RollbackAll

func (rm *RollbackManager) RollbackAll(ctx context.Context, installer port.HelmInstaller, namespace string) error

type SecretEntry

type SecretEntry struct {
	// PathSuffix 는 kv/nullus/{env}/{org}/ 뒤에 붙는 OpenBao 경로다.
	PathSuffix string
	// TargetKey 는 Kubernetes Secret 안의 키 이름이다. 차트가 요구하는 이름과
	// 정확히 일치해야 한다.
	TargetKey string
	// Length 는 생성할 값의 길이다. 0 이면 기본값(secretValueLength)을 쓴다.
	// 길이를 정하는 이유는 취향이 아니다 — Harbor 의 secretKey 처럼 차트가
	// **정확한 길이**를 요구하는 값이 있고, 어긋나면 기동 시 죽는다.
	Length int
	// Fixed 가 비어 있지 않으면 랜덤 생성 대신 이 값을 쓴다.
	// 사용자명처럼 비밀이 아니지만 차트가 같은 Secret 안에서 요구하는 값에 쓴다.
	Fixed string
	// DeriveFrom 과 Derive 가 있으면 랜덤 생성 대신 다른 엔트리의 값에서 계산한다.
	// bcrypt 해시처럼 평문과 짝을 이뤄야 하는 값에 쓴다 — 따로 생성하면 사용자가
	// 안내받은 비밀번호로 로그인할 수 없다.
	//
	// 원본 엔트리가 이 엔트리보다 앞에 있어야 한다(같은 순서로 처리된다).
	DeriveFrom string
	Derive     func(source string) (string, error)
}

SecretEntry 는 대상 Secret 안의 키 하나에 대응한다.

type SecretWriter

type SecretWriter interface {
	PutToken(ctx context.Context, path, value string) error
	GetToken(ctx context.Context, path string) (string, error)
}

SecretWriter 는 OpenBao 에 값을 기록하고 읽는 최소 인터페이스다.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL