Documentation
¶
Overview ¶
Package identity holds the agent's per-cluster mTLS identity.
The private key is generated on the cluster and never leaves it. Enrollment sends a certificate signing request; the SaaS signs it and returns a certificate. That is the difference between a vendor who can impersonate a customer's cluster and one who demonstrably cannot — and it is a property of where the key is made, not of anyone's good intentions.
Index ¶
- Constants
- Variables
- func CSR(key *ecdsa.PrivateKey, clusterID string) ([]byte, error)
- func Exists(dir string) bool
- func Fingerprint(pub *ecdsa.PublicKey) (string, error)
- func LoadServer(dir string) (string, error)
- func NewKey() (*ecdsa.PrivateKey, error)
- func PublicKeyOf(k *ecdsa.PrivateKey) *ecdsa.PublicKey
- func Remove(dir string) error
- func SaveServer(dir, addr string) error
- type EnrollRequest
- type EnrollResponse
- type Enroller
- type Identity
Constants ¶
const (
DefaultDir = "/etc/cube/advisor-agent"
)
Default locations on a CubeCOS node.
Variables ¶
var ( ErrTokenRejected = errors.New("identity: pairing token rejected") ErrAlreadyEnrolled = errors.New("identity: this node already has an identity") )
Enrollment errors a caller should distinguish, because the operator's next action differs for each: get a fresh token, fix connectivity, or re-enroll.
Functions ¶
func CSR ¶
func CSR(key *ecdsa.PrivateKey, clusterID string) ([]byte, error)
CSR returns a PEM certificate signing request for clusterID.
It carries the public key and the cluster's name. It does not, and must not, carry the private key — see the test that inspects the bytes.
func Exists ¶
Exists reports whether dir already holds a key and certificate. Enrollment consults this so a second run cannot silently replace a working identity — re-enrolling is a deliberate act, not an accident of running a command twice.
func Fingerprint ¶
Fingerprint is the SHA-256 of the public key in SPKI form, base64 encoded and prefixed — the same shape ssh prints.
This is the value an operator compares on screen during enrollment verify, so it must derive from the key alone: it has to be computable before a certificate exists, and identical on both sides.
func LoadServer ¶
LoadServer reads the tunnel address SaveServer persisted. A missing file is not an error — it just means enrolment predates this feature, or never resolved an address — so the caller (run) can fall back to requiring -server explicitly instead of failing to load an identity that is otherwise fine.
func NewKey ¶
func NewKey() (*ecdsa.PrivateKey, error)
NewKey generates a fresh keypair on this machine.
P-256 rather than Ed25519: it is what every TLS stack and every FIPS module on the target platforms already accepts, and enrollment is not the place to spend novelty budget.
func PublicKeyOf ¶
func PublicKeyOf(k *ecdsa.PrivateKey) *ecdsa.PublicKey
PublicKeyOf exposes a key's public half, for callers computing a fingerprint before enrolment.
func Remove ¶
Remove deletes a stored identity.
Used only by an explicit re-enrolment. It is a separate function rather than something Save does implicitly, because silently replacing an identity is how a cluster loses the certificate the SaaS is currently accepting.
func SaveServer ¶
SaveServer persists the tunnel address enrolment resolved, so a later `run` needs no operator argument. Mode 0644, unlike the key: this is not secret, it is the same host:port an operator could read straight off the SaaS.
It is a separate write from Save rather than a field on it, so an existing caller of Save is unaffected and a failure to persist the address (a read-only /etc, say) never looks like a failure to persist the identity.
Types ¶
type EnrollRequest ¶
type EnrollRequest = enrollproto.Request
The wire shapes live in pkg/enrollproto, which the SaaS imports too — one definition rather than two that must be kept in step.
type EnrollResponse ¶
type EnrollResponse = enrollproto.Response
The wire shapes live in pkg/enrollproto, which the SaaS imports too — one definition rather than two that must be kept in step.
type Enroller ¶
type Enroller struct {
// BaseURL of the SaaS enrollment endpoint.
BaseURL string
// HTTPClient is overridable for tests and for sites behind an egress proxy.
HTTPClient *http.Client
// AgentVersion is reported so an operator can see what enrolled.
AgentVersion string
}
Enroller exchanges a pairing token for a signed identity.
func (*Enroller) Enroll ¶
Enroll generates a key, requests a certificate for clusterID with the pairing token, and returns the resulting identity. It does not write anything to disk; the caller decides where an identity lives.
The token authenticates this one request and is deliberately not stored: it is single-use, and an unused copy on disk is a credential nobody is watching.
func (*Enroller) EnrollAndSave ¶
func (e *Enroller) EnrollAndSave(ctx context.Context, dir, clusterID, token string) (*Identity, error)
EnrollAndSave is the operator-facing path: enroll, then persist to dir.
It refuses when dir already holds an identity. Re-enrolling should be a deliberate act — running the command twice must not quietly invalidate the certificate the SaaS is currently accepting.
type Identity ¶
type Identity struct {
ClusterID string
// contains filtered or unexported fields
}
Identity is the agent's cluster identity: a private key that never leaves, the certificate the SaaS signed for it, and the CA that certificate chains to.
func Load ¶
Load reads an identity from dir.
It refuses a private key whose mode is looser than 0600. A key other users can read is not an identity, and continuing with a warning would make the agent's own logs the only record that its identity was readable.
func (*Identity) Fingerprint ¶
Fingerprint of this identity.