secretsmanager

package
v0.19.1101 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package secretsmanager manages the phone-home secret in the management account's AWS Secrets Manager.

The secret always lives in AWS regardless of which cloud the control plane runs on, because the reader is the customer's phone-home Lambda and Secrets Manager is the only store it can reach. Which credentials get us there is decided once, by internal.Config.ManagementSecretsCreds.

Index

Constants

View Source
const (
	TagKeyOrgID        = "org.nuon.co/id"
	TagKeyInstallID    = "install.nuon.co/id"
	TagKeyRunnerAPIURL = "runner_api_url"
	TagKeyEnv          = "env"
)

Tag keys on the phone-home secret. The secret name carries only the install ID, so without these there is no way to answer "which org owns this?" or "is this from staging?" from the AWS console or a cost report — every secret in the management account looks identical apart from an opaque ID.

The domain-qualified form matches how Nuon labels resources elsewhere; runner_api_url and env are plain because they are environment facts rather than entity references.

Variables

View Source
var ErrUnsupportedCloud = errors.New("control plane cannot reach management secrets manager")

ErrUnsupportedCloud is returned when this control plane has no path to the management account's Secrets Manager. Callers treat it as "skip", not "fail".

Functions

func PhoneHomeResourcePolicy

func PhoneHomeResourcePolicy(targetAccountID, phoneHomeRoleName string) (string, error)

PhoneHomeResourcePolicy grants the install's phone-home role read access to its own secret. Per-install isolation comes from this policy rather than from the CMK key policy, which is why one shared key is sufficient.

The role is named in a Condition rather than as the Principal, because the role does not exist when this first runs and Secrets Manager validates principals: naming it directly fails the whole call with

MalformedPolicyDocumentException: This resource policy contains an unsupported principal

The ordering that forces this cannot be reversed. The role is created by the customer's CloudFormation stack, but the Lambda reads this secret *during* that stack's creation, so the policy has to be in place first. (An install whose stack already ran does have the role, which is why this only ever failed on fresh installs — a difference worth knowing about before "it worked before" is taken as evidence of a regression.)

The account root always resolves, so it is the Principal, and aws:PrincipalArn pins the grant to the one role at evaluation time. The effective boundary is the same as naming the role directly, with one caveat: root as Principal delegates to the target account's own IAM, so a principal there needs an identity policy allowing GetSecretValue on this ARN as well. The stack grants exactly that to the phone-home role and nothing else (getRunnerPhoneHomeLambdaRole), so reaching the secret still takes both halves — but a customer administrator in that account could write themselves a third. Account-level containment is the real boundary here, and the target account is the customer's own.

A typo in the role name still fails silently, as an AccessDeniedException at phone-home time rather than an error here, which is why the render tests assert the name.

func PhoneHomeSecretName

func PhoneHomeSecretName(installID string) string

PhoneHomeSecretName is deterministic, unlike the ARN it resolves to.

func PhoneHomeSecretTags

func PhoneHomeSecretTags(orgID, installID, runnerAPIURL, env string) map[string]string

PhoneHomeSecretTags identifies which install and org a secret belongs to, and which control plane created it.

runner_api_url and env together disambiguate control planes that share a management account: a dev, staging and production ctl-api all write secrets named nuon/phone-home/<install_id>, and install IDs do not collide but nothing else distinguishes who owns a given entry. Empty values are dropped rather than written as empty tags.

Types

type EnsureSecretInput

type EnsureSecretInput struct {
	Name        string
	Value       string
	Description string
	// KMSKeyARN encrypts the secret. When empty the AWS-managed key is used, which
	// cannot be read cross-account — acceptable only before the shared CMK exists.
	KMSKeyARN string
	// Tags are applied on create and reconciled on every later call, because
	// CreateSecret is the only call that accepts them — secrets provisioned before a
	// tag was added would otherwise never get it. Only added and updated, never
	// removed: something outside this reconciler may have tagged the secret for cost
	// allocation or policy and deleting those would be a surprise.
	Tags map[string]string
}

type EnsureSecretOutput

type EnsureSecretOutput struct {
	ARN    string
	Region string
	// Wrote reports whether a new secret version was actually written. False means
	// the stored value already matched, which is the common case across repeated
	// stack generations.
	Wrote bool
}

type Service

type Service interface {
	// EnsureSecret creates the secret or updates its value, and returns the full
	// ARN. The ARN is not derivable from the name — AWS appends a random 6-char
	// suffix and cross-account reads reject a bare name — so callers must persist
	// what this returns.
	EnsureSecret(ctx context.Context, input EnsureSecretInput) (*EnsureSecretOutput, error)

	// PutResourcePolicy replaces the secret's resource policy. Full replacement,
	// not a merge.
	PutResourcePolicy(ctx context.Context, secretID, policy string) error

	// DeleteSecret removes the secret without a recovery window. The default 7-30
	// day window would make re-provisioning the same install ID fail with
	// InvalidRequestException.
	DeleteSecret(ctx context.Context, secretID string) error
}

Service manages secrets in the management account.

func NewService

func NewService(cfg *internal.Config, l *zap.Logger) Service

Jump to

Keyboard shortcuts

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