diff --git a/.github/renovate.json b/.github/renovate.json index 266b8d8a..24c4c5f9 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -105,7 +105,6 @@ ] }, { - "allowedVersions": "< 3.0.0", "matchPackageNames": [ "https://gitlab.nic.cz/labs/bird.git" ] diff --git a/.kres.yaml b/.kres.yaml index 6ed17955..8c4ce1aa 100644 --- a/.kres.yaml +++ b/.kres.yaml @@ -5,6 +5,7 @@ spec: - amazon-ena - amdgpu - amd-ucode + - aws-iam-authenticator - binfmt-misc - bird2 - bnx2-bnx2x diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 3141941e..cf567f77 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -13,6 +13,7 @@ If the field is marked as `Needs Maintainer`, it means that the package is curre | amazon-ena | Sidero Labs | NA | | amdgpu | Sidero Labs | NA | | amd-ucode | Sidero Labs | NA | +| aws-iam-authenticator | Fábio Matavelli | [fabiomatavelli](https://github.com/fabiomatavelli) | | binfmt-misc | Serge Logvinov | [sergelogvinov](https://github.com/sergelogvinov) | | bnx2-bnx2x | Sidero Labs | NA | | btrfs | Enno Boland | [Gottox](https://github.com/Gottox) | diff --git a/Makefile b/Makefile index ff9d3bbc..b7acb368 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-12-24T16:04:12Z by kres 26be706. +# Generated on 2026-01-02T15:53:16Z by kres 8a4aebf. # common variables @@ -37,6 +37,7 @@ PLATFORM ?= linux/amd64,linux/arm64 PROGRESS ?= auto PUSH ?= false CI_ARGS ?= +WITH_BUILD_DEBUG ?= BUILD_ARGS = --build-arg=SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) BUILD_ARGS += --build-arg=TAG="$(TAG)" BUILD_ARGS += --build-arg=PKGS="$(PKGS)" @@ -63,6 +64,7 @@ IMAGE_SIGNER_RELEASE ?= v0.1.1 TARGETS = amazon-ena TARGETS += amdgpu TARGETS += amd-ucode +TARGETS += aws-iam-authenticator TARGETS += binfmt-misc TARGETS += bird2 TARGETS += bnx2-bnx2x @@ -189,6 +191,10 @@ respectively. endef +ifneq (, $(filter $(WITH_BUILD_DEBUG), t true TRUE y yes 1)) +BUILD := BUILDX_EXPERIMENTAL=1 docker buildx debug --invoke /bin/sh --on error build +endif + all: $(TARGETS) ## Builds all targets defined. $(ARTIFACTS): ## Creates artifacts directory. diff --git a/container-runtime/aws-iam-authenticator/README.md b/container-runtime/aws-iam-authenticator/README.md new file mode 100644 index 00000000..7bce06f9 --- /dev/null +++ b/container-runtime/aws-iam-authenticator/README.md @@ -0,0 +1,173 @@ +# AWS IAM Authenticator Extension + +This extension provides the [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator) for Talos Linux. The AWS IAM Authenticator allows you to use AWS IAM credentials to authenticate to your Kubernetes cluster, eliminating the need to manage static kubeconfig files. + +## Overview + +The extension includes: +- The `aws-iam-authenticator` binary for server-side authentication +- A custom init wrapper that generates certificates and kubeconfig files on node startup +- Support for configurable init parameters via environment variables + +When installed, the extension runs during node initialization to generate the necessary certificates, private keys, and webhook kubeconfig files required for the kube-apiserver to authenticate users via AWS IAM. + +## Installation + +See [Installing Extensions](https://github.com/siderolabs/extensions#installing-extensions). + +## Configuration + +### 1. Extension Service Configuration + +Configure the extension via `ExtensionServiceConfig` document. Below is an example with all available environment variables: + +```yaml +# aws-iam-authenticator-config.yaml +--- +apiVersion: v1alpha1 +kind: ExtensionServiceConfig +name: aws-iam-authenticator +environment: + # Required: Cluster identifier (must match the cluster ID used by clients) + - CLUSTER_ID=my-cluster + # Optional: Hostname for self-signed certificates (default: localhost) + - HOSTNAME=kubernetes.example.com + # Optional: IP address to bind the server to (default: 127.0.0.1) + - ADDRESS=127.0.0.1 + # Optional: Path to configuration file + - CONFIG_FILE=/usr/local/lib/aws-iam-authenticator/config.yaml + # Optional: Log format (text or json) + - LOG_FORMAT=json +``` + +Then apply the patch to your node's MachineConfigs: +```bash +talosctl patch mc -p @aws-iam-authenticator-config.yaml +``` + +You can verify that it is in place with the following command: +```bash +talosctl get extensionserviceconfigs + +NODE NAMESPACE TYPE ID VERSION +mynode runtime ExtensionServiceConfig aws-iam-authenticator 1 +``` + +**Environment Variables:** + +| Variable | Required | Default | Description | +|----------|----------|---------|-------------| +| `CLUSTER_ID` | Yes | - | Unique cluster identifier. Must match the `-i` flag used by clients to prevent replay attacks across clusters. | +| `HOSTNAME` | No | `localhost` | Hostname used when generating self-signed certificates. Set this to your API server's hostname. | +| `ADDRESS` | No | `127.0.0.1` | IP address the authenticator server will bind to. Use `127.0.0.1` for local-only or `0.0.0.0` to listen on all interfaces. | +| `CONFIG_FILE` | No | - | Path to a configuration file for advanced settings (role mappings, backend mode, etc.). | +| `LOG_FORMAT` | No | `text` | Log output format. Options: `text` or `json`. | + +### 2. Kube-APIServer Configuration + +After installing the extension, you must configure the kube-apiserver to use the webhook authentication method. Add the following to your Talos cluster configuration: + +```yaml +cluster: + apiServer: + extraArgs: + authentication-token-webhook-config-file: /usr/local/lib/aws-iam-authenticator/kubeconfig.yaml + extraVolumes: + - hostPath: /usr/local/lib/aws-iam-authenticator + mountPath: /usr/local/lib/aws-iam-authenticator + readOnly: true +``` + +**What this does:** +- `authentication-token-webhook-config-file`: Tells the kube-apiserver to validate bearer tokens using the webhook configuration generated by aws-iam-authenticator +- The volume mount gives the API server access to the generated kubeconfig and certificates + +### 3. AWS IAM Authenticator Server DaemonSet + +After the init process generates the certificates and kubeconfig, you need to deploy the aws-iam-authenticator server as a DaemonSet on control plane nodes. + +**Important:** Make sure to configure the DaemonSet with the following requirements: +- Point `--config`, `--state-dir`, and `--generate-kubeconfig` to `/usr/local/lib/aws-iam-authenticator` +- Include the `--kubeconfig-pregenerated=true` flag since the extension has already generated the kubeconfig +- Mount `/usr/local/lib/aws-iam-authenticator` from the host + +See [example-daemonset.yaml](example-daemonset.yaml) for a complete working example. + +### 4. Client Configuration and IAM Role Mapping + +For client-side configuration and IAM role/user mapping to Kubernetes RBAC groups, please refer to the official documentation: + +- [Client Setup - Installing aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator#4-set-up-kubectl-to-use-authentication-tokens-provided-by-aws-iam-authenticator-for-kubernetes) +- [IAM Role Mapping Configuration](https://github.com/kubernetes-sigs/aws-iam-authenticator#full-configuration-format) + +## How It Works + +1. **Initialization**: When a Talos node boots, the extension service runs the init wrapper which executes `aws-iam-authenticator init` +2. **Certificate Generation**: The init command generates: + - Self-signed certificates for the webhook server + - A webhook kubeconfig file at `/usr/local/lib/aws-iam-authenticator/kubeconfig.yaml` +3. **API Server Integration**: The kube-apiserver uses the generated kubeconfig to validate authentication tokens via webhook +4. **Authentication Flow**: + - Client runs `aws-iam-authenticator token -i ` to generate a token + - Client sends the token to the API server in the Authorization header + - API server forwards the token to the webhook endpoint + - The authenticator validates the AWS signature and returns the user identity and groups + - API server applies RBAC based on the returned groups + +## Service Management + +The extension service appears in the service list with the `ext-` prefix. Since the init process runs once and exits, the service will show as "Finished": + +```bash +$ talosctl services +NODE SERVICE STATE HEALTH LAST CHANGE +172.20.0.5 ext-aws-iam-authenticator Finished ? 1m38s ago +``` + +View detailed service information: + +```bash +$ talosctl service ext-aws-iam-authenticator +``` + +View service logs: + +```bash +$ talosctl logs ext-aws-iam-authenticator +``` + +## Troubleshooting + +### Check Generated Files + +Verify that the init process generated the necessary files: + +```bash +$ talosctl ls /usr/local/lib/aws-iam-authenticator/ +. +.. +cert.pem +key.pem +kubeconfig.yaml +``` + +### Verify Cluster ID + +Ensure the `CLUSTER_ID` in your extension configuration matches the `-i` parameter used by clients: + +```bash +$ talosctl logs ext-aws-iam-authenticator | grep "executing" +executing: /usr/local/bin/aws-iam-authenticator [init -i=my-cluster] +``` + +### Common Issues + +- **Authentication fails**: Verify cluster IDs match between server and client +- **Permission denied**: Check that the API server can read `/usr/local/lib/aws-iam-authenticator/kubeconfig.yaml` +- **Certificate errors**: Ensure `HOSTNAME` matches your API server's hostname if using TLS + +## References + +- [aws-iam-authenticator GitHub Repository](https://github.com/kubernetes-sigs/aws-iam-authenticator) +- [EKS Anywhere - IAM Authentication](https://anywhere.eks.amazonaws.com/docs/clustermgmt/security/cluster-iam-auth/) +- [AWS Best Practices - Identity and Access Management](https://docs.aws.amazon.com/eks/latest/best-practices/identity-and-access-management.html) diff --git a/container-runtime/aws-iam-authenticator/aws-iam-authenticator.yaml b/container-runtime/aws-iam-authenticator/aws-iam-authenticator.yaml new file mode 100644 index 00000000..2e5793ad --- /dev/null +++ b/container-runtime/aws-iam-authenticator/aws-iam-authenticator.yaml @@ -0,0 +1,24 @@ +name: aws-iam-authenticator +depends: + - service: cri + - network: + - addresses + - connectivity + - etcfiles + - configuration: true + - time: true +container: + entrypoint: ./init + environment: + - PATH=/sbin:/usr/local/bin + security: + writeableRootfs: true +mounts: + - destination: /usr/local/lib/aws-iam-authenticator + type: bind + source: /usr/local/lib/aws-iam-authenticator + options: + - rbind + - rshared + - rw +restart: never diff --git a/container-runtime/aws-iam-authenticator/example-daemonset.yaml b/container-runtime/aws-iam-authenticator/example-daemonset.yaml new file mode 100644 index 00000000..4061515c --- /dev/null +++ b/container-runtime/aws-iam-authenticator/example-daemonset.yaml @@ -0,0 +1,125 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: aws-iam-authenticator + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aws-iam-authenticator +rules: + - apiGroups: + - iamauthenticator.k8s.aws + resources: + - iamidentitymappings + verbs: + - get + - list + - watch + - apiGroups: + - iamauthenticator.k8s.aws + resources: + - iamidentitymappings/status + verbs: + - patch + - update + - apiGroups: + - "" + resources: + - events + verbs: + - create + - update + - patch + - apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - aws-auth + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: aws-iam-authenticator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: aws-iam-authenticator +subjects: + - kind: ServiceAccount + name: aws-iam-authenticator + namespace: kube-system +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + namespace: kube-system + name: aws-iam-authenticator + labels: + k8s-app: aws-iam-authenticator +spec: + selector: + matchLabels: + k8s-app: aws-iam-authenticator + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + k8s-app: aws-iam-authenticator + spec: + serviceAccountName: aws-iam-authenticator + hostNetwork: true + nodeSelector: + node-role.kubernetes.io/control-plane: "" + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + - key: CriticalAddonsOnly + operator: Exists + priorityClassName: system-cluster-critical + containers: + - name: aws-iam-authenticator + image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-iam-authenticator:v0.7.10 + args: + - server + # IMPORTANT: Point to the pre-generated files from the extension + - --config=/usr/local/lib/aws-iam-authenticator/config.yaml + - --state-dir=/usr/local/lib/aws-iam-authenticator + - --generate-kubeconfig=/usr/local/lib/aws-iam-authenticator/kubeconfig.yaml + # IMPORTANT: Use pre-generated kubeconfig from the extension init process + - --kubeconfig-pregenerated=true + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + resources: + requests: + memory: 20Mi + cpu: 10m + limits: + memory: 20Mi + cpu: 100m + volumeMounts: + - name: state + mountPath: /usr/local/lib/aws-iam-authenticator/ + volumes: + - name: state + hostPath: + path: /usr/local/lib/aws-iam-authenticator/ + type: Directory diff --git a/container-runtime/aws-iam-authenticator/manifest.yaml.tmpl b/container-runtime/aws-iam-authenticator/manifest.yaml.tmpl new file mode 100644 index 00000000..87053f4c --- /dev/null +++ b/container-runtime/aws-iam-authenticator/manifest.yaml.tmpl @@ -0,0 +1,10 @@ +version: v1alpha1 +metadata: + name: aws-iam-authenticator + version: "{{ .VERSION }}" + author: Fábio Matavelli + description: | + [{{ .TIER }}] This system extension provides aws-iam-authenticator init process to generate certificates and kubeconfig for AWS IAM authentication with Kubernetes. + compatibility: + talos: + version: ">= v1.11.0" diff --git a/container-runtime/aws-iam-authenticator/pkg.yaml b/container-runtime/aws-iam-authenticator/pkg.yaml new file mode 100644 index 00000000..2d52f9d1 --- /dev/null +++ b/container-runtime/aws-iam-authenticator/pkg.yaml @@ -0,0 +1,52 @@ +name: aws-iam-authenticator +variant: scratch +shell: /bin/bash +dependencies: + - stage: base +steps: + - sources: + # {{ if eq .ARCH "arm64" }} + - url: https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v{{ .AWS_IAM_AUTHENTICATOR_VERSION }}/aws-iam-authenticator_{{ .AWS_IAM_AUTHENTICATOR_VERSION }}_linux_arm64 + destination: aws-iam-authenticator + sha256: {{ .AWS_IAM_AUTHENTICATOR_ARM64_SHA256 }} + sha512: {{ .AWS_IAM_AUTHENTICATOR_ARM64_SHA512 }} + # {{ else }} + - url: https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v{{ .AWS_IAM_AUTHENTICATOR_VERSION }}/aws-iam-authenticator_{{ .AWS_IAM_AUTHENTICATOR_VERSION }}_linux_amd64 + destination: aws-iam-authenticator + sha256: {{ .AWS_IAM_AUTHENTICATOR_AMD64_SHA256 }} + sha512: {{ .AWS_IAM_AUTHENTICATOR_AMD64_SHA512 }} + # {{ end }} + env: + GOPATH: /go + build: + - | + cd /pkg/src + CGO_ENABLED=0 go build -o ./aws-iam-authenticator-init . + install: + - | + mkdir -p /rootfs/usr/local/lib/containers/aws-iam-authenticator + + cp -p /pkg/src/aws-iam-authenticator-init /rootfs/usr/local/lib/containers/aws-iam-authenticator/init + - | + mkdir -p /rootfs/usr/local/bin + mv -v aws-iam-authenticator /rootfs/usr/local/bin + chmod +x /rootfs/usr/local/bin/aws-iam-authenticator + - | + mkdir -p /rootfs/usr/local/etc/containers + cp /pkg/aws-iam-authenticator.yaml /rootfs/usr/local/etc/containers/ + test: + - | + mkdir -p /extensions-validator-rootfs + cp -r /rootfs/ /extensions-validator-rootfs/rootfs + cp /pkg/manifest.yaml /extensions-validator-rootfs/manifest.yaml + /extensions-validator validate --rootfs=/extensions-validator-rootfs --pkg-name="${PKG_NAME}" + sbom: + outputPath: /rootfs/usr/local/share/spdx/aws-iam-authenticator.spdx.json + version: {{ .AWS_IAM_AUTHENTICATOR_VERSION }} + licenses: + - Apache-2.0 +finalize: + - from: /rootfs + to: /rootfs + - from: /pkg/manifest.yaml + to: / \ No newline at end of file diff --git a/container-runtime/aws-iam-authenticator/src/go.mod b/container-runtime/aws-iam-authenticator/src/go.mod new file mode 100644 index 00000000..c895e551 --- /dev/null +++ b/container-runtime/aws-iam-authenticator/src/go.mod @@ -0,0 +1,3 @@ +module aws-iam-authenticator + +go 1.24 diff --git a/container-runtime/aws-iam-authenticator/src/main.go b/container-runtime/aws-iam-authenticator/src/main.go new file mode 100644 index 00000000..34daea9e --- /dev/null +++ b/container-runtime/aws-iam-authenticator/src/main.go @@ -0,0 +1,63 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package main + +import ( + "fmt" + "log" + "os" + "os/exec" +) + +func main() { + log.Printf("starting the aws-iam-authenticator init process") + defer log.Printf("finishing the aws-iam-authenticator init process") + + // Create the working directory + workDir := "/usr/local/lib/aws-iam-authenticator" + if err := os.MkdirAll(workDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "Error creating directory %s: %v\n", workDir, err) + os.Exit(1) + } + + // Change to the working directory + if err := os.Chdir(workDir); err != nil { + fmt.Fprintf(os.Stderr, "Error changing to directory %s: %v\n", workDir, err) + os.Exit(1) + } + + args := []string{"init"} + + if clusterID := os.Getenv("CLUSTER_ID"); clusterID != "" { + args = append(args, fmt.Sprintf("-i=%s", clusterID)) + } + + if hostname := os.Getenv("HOSTNAME"); hostname != "" { + args = append(args, fmt.Sprintf("--hostname=%s", hostname)) + } + + if address := os.Getenv("ADDRESS"); address != "" { + args = append(args, fmt.Sprintf("--address=%s", address)) + } + + if config := os.Getenv("CONFIG_FILE"); config != "" { + args = append(args, fmt.Sprintf("--config=%s", config)) + } + + if logFormat := os.Getenv("LOG_FORMAT"); logFormat != "" { + args = append(args, fmt.Sprintf("--log-format=%s", logFormat)) + } + + log.Printf("executing: /usr/local/bin/aws-iam-authenticator %v", args) + + cmd := exec.Command("/usr/local/bin/aws-iam-authenticator", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} diff --git a/container-runtime/aws-iam-authenticator/vars.yaml b/container-runtime/aws-iam-authenticator/vars.yaml new file mode 100644 index 00000000..d44b2e50 --- /dev/null +++ b/container-runtime/aws-iam-authenticator/vars.yaml @@ -0,0 +1,2 @@ +VERSION: "{{ .AWS_IAM_AUTHENTICATOR_VERSION }}" +TIER: "contrib" \ No newline at end of file diff --git a/container-runtime/vars.yaml b/container-runtime/vars.yaml index 31ce63e8..20b76a77 100644 --- a/container-runtime/vars.yaml +++ b/container-runtime/vars.yaml @@ -50,3 +50,9 @@ YOUKI_ARM64_SHA256: b3002d9d39b04f797e783745f92cffec9e0caa464254be98aa0b4dfc184f YOUKI_ARM64_SHA512: 569883c18923c533e2b697b367757cde3f4a71b41a33b0b83b2b6c189f2ddb399cfeafbd4e7c7f219150987309fb529260f29b579abf14b52fb0e416217d9638 YOUKI_AMD64_SHA256: a9003472a6e959f345db8e48371a335ab98fae53a5e71a4339b5fe54f0691f60 YOUKI_AMD64_SHA512: 5574e632c954709101deb9320d49ee23763ecd6993e5de5e3b55e6506608e65f11d6d481d7a0d94f5ac9abe09d5d04b6590f8d5bfdeeb2394db570b80cf48263 +# renovate: datasource=github-release extractVersion=^v(?.*)$ depName=kubernetes-sigs/aws-iam-authenticator +AWS_IAM_AUTHENTICATOR_VERSION: 0.7.10 +AWS_IAM_AUTHENTICATOR_ARM64_SHA256: 43956e8e7ea05f9558d82134a0da2651cdc1194594b2c86b8a43cb635f4810be +AWS_IAM_AUTHENTICATOR_ARM64_SHA512: 5d292bef179d10d1cd54aa1526eb81fa52d302d488c2446e1148ea3dadfceb0ffef43831ca2da6d218ac2dd9c489780bbaf7f15c31372323f6b0430864681d39 +AWS_IAM_AUTHENTICATOR_AMD64_SHA256: bb9faba1d0689de722b819e5ab3cd0782f1b88b6cf0a75455759cecbe1d96802 +AWS_IAM_AUTHENTICATOR_AMD64_SHA512: 5a044e03cf0bc9f4bc3998d56379f303e6f3f26e38b21b9102a25959d06c42eb7ceeb8e267a5cfb044d3822a00fce2a1ff66ebedc4de428947837ee61205c5bf \ No newline at end of file