Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions aks-node-controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ recursively deleting directories or removing installed system-trust certificates
`AKS_CLOUD_LOG_CERTIFICATES=true` enables public-certificate-only diagnostics;
parsing for logging does not gate installation.

These are internal capabilities only. Existing provisioning still uses
`init-aks-cloud.sh`.
Existing provisioning still uses `init-aks-cloud.sh`; these helpers do not change
the provisioning entry point.

### Azure cloud certificate retrieval capabilities

Expand All @@ -94,9 +94,36 @@ returning partial certificate bytes, unlike the shell's status-only success
check. This is not certificate-content validation: a close-delimited response
without a length or chunk-framing error can still contain incomplete content.

Retrieval does not install certificates or make opt-in decisions. Refresh
orchestration, the standalone refresh command, scheduling, and native provisioning
activation are supplied by later layers; they are not enabled here.
Retrieval helpers do not install certificates or make opt-in decisions; the refresh
orchestration below combines those capabilities. Repository configuration,
scheduling, and native provisioning activation are supplied by later layers.

### Azure cloud certificate refresh

ANC provides a standalone command for refreshing Azure cloud CA certificates:

```sh
/opt/azure/containers/aks-node-controller refresh-cloud-certificates --location westus2
```

Regions starting with `ussec` or `usnat` use the legacy certificate endpoint.
Other regions check WireServer's root-certificate opt-in before retrieving root
and intermediate certificates. Only the JSON boolean `true` enables opt-in;
nonempty malformed or non-true responses skip installation. Failed or empty
opt-in requests remain errors. Individual operation-certificate download failures
are logged and skipped, and legacy trust-store installation failures remain
best-effort unless the context is canceled.

Downloaded contents are passed to the system trust-store tools without additional
PEM/X.509 validation. Refresh clears the flat staging cache, including hidden
files, without removing existing system trust-store certificates. Raw responses
are never logged; `AKS_CLOUD_LOG_CERTIFICATES=true` enables public-certificate-only
diagnostics. The refresh command has a 15-minute budget and emits
`CloudCertificateRefresh` guest-agent events.

This command does not configure repositories or install refresh schedules.
Existing provisioning still uses `init-aks-cloud.sh`; native cloud initialization
is not yet connected to the provisioning entry point.

### Validating and normalizing AKSNodeConfig

Expand Down
15 changes: 15 additions & 0 deletions aks-node-controller/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ type App struct {
// grpcDialContext overrides how the gRPC LPS client dials, letting tests point the client at
// an in-process (bufconn) server. When nil, the real TLS dial to the apiserver front is used.
grpcDialContext func(ctx context.Context, target string) (net.Conn, error)
// refreshCloudCertificates overrides standalone cloud certificate refresh for testing.
refreshCloudCertificates func(context.Context, string) error
}

// provision.json values are emitted as strings by the shell jq invocation.
Expand Down Expand Up @@ -184,6 +186,19 @@ func (a *App) Run(ctx context.Context, args []string) int {
return nil
},
},
{
Name: "refresh-cloud-certificates",
Usage: "Refresh Azure cloud CA certificates without configuring repositories",
Flags: []cli.Flag{
&cli.StringFlag{Name: "location", Required: true, Usage: "Azure region used to select the certificate endpoint"},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
if cmd.Args().Len() != 0 {
return fmt.Errorf("unexpected refresh-cloud-certificates arguments: %s", strings.Join(cmd.Args().Slice(), " "))
}
return a.runCloudCertificateRefresh(ctx, cmd.String("location"))
},
},
{
Name: "download-hotfix",
Usage: "Download the requested hotfix binary",
Expand Down
57 changes: 57 additions & 0 deletions aks-node-controller/cloud_certificates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"strings"
)

func (c *cloudInitializer) refresh(ctx context.Context, platform cloudPlatform, location string) (bool, error) {
c.clearCertificateCache()
legacy := strings.HasPrefix(location, "ussec") || strings.HasPrefix(location, "usnat")
slog.Info("selecting Azure cloud certificate endpoint", "legacy", legacy, "location", location)
if !legacy {
body, err := c.requestCertificates(ctx, "/acms/isOptedInForRootCerts")
if err != nil {
return false, fmt.Errorf("check Azure cloud root certificate opt-in: %w", err)
}
if len(bytes.TrimRight(body, "\n")) == 0 {
return false, errors.New("cloud root certificate opt-in response is empty")
}
var response map[string]json.RawMessage
if err := json.Unmarshal(body, &response); err != nil {
slog.Warn("could not decode Azure cloud root certificate opt-in, skipping certificate installation", "error", err)
return false, nil
}
if !bytes.Equal(bytes.TrimSpace(response["IsOptedInForRootCerts"]), []byte("true")) {
slog.Info("Azure cloud root certificates are not opted in, skipping certificate installation")
return false, nil
}
}
var certificates map[string][]byte
var err error
if legacy {
certificates, err = c.legacyCertificates(ctx)
} else {
certificates, err = c.operationCertificates(ctx)
}
if err != nil {
return false, err
}
if err := c.installCertificates(ctx, platform, certificates); err != nil {
if ctx.Err() != nil {
return false, ctx.Err()
}
if legacy {
slog.Warn("legacy Azure cloud CA certificate installation failed, continuing cloud initialization", "error", err)
return true, nil
}
return false, fmt.Errorf("install Azure cloud CA certificates: %w", err)
}
slog.Info("installed Azure cloud CA certificates")
return true, nil
}
Loading
Loading