first commit
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
|||||||
|
# Terraform state, plans, and provider/plugin caches
|
||||||
|
**/.terraform/
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.*
|
||||||
|
*.tfplan
|
||||||
|
crash.log
|
||||||
|
crash.*.log
|
||||||
|
.terraform.lock.hcl
|
||||||
|
|
||||||
|
# Ansible artifacts and local secrets
|
||||||
|
*.retry
|
||||||
|
*.vault-password
|
||||||
|
ansible/inventory/*.ini
|
||||||
|
ansible/inventory/*.yml
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# Local tooling and generated demo output
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
|
tmp/
|
||||||
|
artifacts/
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Kubernetes Security Baseline
|
||||||
|
|
||||||
|
An auditable, GitOps-managed Kubernetes security baseline: local k3d for a
|
||||||
|
fast reproducible demo, optional Terraform + Ansible for a cloud K3s host, CIS
|
||||||
|
Benchmark checks in CI, Kyverno admission policies, and Falco runtime
|
||||||
|
detection.
|
||||||
|
|
||||||
|
## Phase 1: provision a local cluster
|
||||||
|
|
||||||
|
The primary quick-start path requires Docker, k3d, and kubectl:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
k3d cluster create --config local-quickstart/k3d-cluster-config.yaml
|
||||||
|
kubectl get nodes -o wide
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected result: one server and two agent nodes in `Ready` state. The bundled
|
||||||
|
Traefik is disabled so later ArgoCD-managed components own add-ons explicitly.
|
||||||
|
|
||||||
|
Delete the lab with `k3d cluster delete security-baseline`.
|
||||||
|
|
||||||
|
## Production-style option
|
||||||
|
|
||||||
|
`terraform/cloud-cluster/` and `ansible/bootstrap-k3s.yml` provide an optional,
|
||||||
|
documented AWS path. It requires your own AWS credentials, an existing EC2 key
|
||||||
|
pair, an Ubuntu AMI ID for the chosen region, and a tightly scoped admin CIDR.
|
||||||
|
It is not needed for the portfolio demo and is not run in CI.
|
||||||
|
|
||||||
|
## Build status
|
||||||
|
|
||||||
|
- [x] Phase 1: local k3d definition and optional Terraform/Ansible path
|
||||||
|
- [ ] Phase 2: ArgoCD app-of-apps deployment (scaffolded; runtime verification pending)
|
||||||
|
- [ ] Phase 3: kube-bench CI scan
|
||||||
|
- [ ] Phase 4: Kyverno policy set and CIS mapping
|
||||||
|
- [ ] Phase 5: Falco rules and webhook alerting
|
||||||
|
- [ ] Phase 6: test workloads and evidence capture
|
||||||
|
- [ ] Phase 7: architecture/design documentation
|
||||||
|
- [ ] Phase 8: final portfolio polish
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Optional Ansible bootstrap
|
||||||
|
|
||||||
|
The playbook applies a small host baseline (AppArmor, unattended security
|
||||||
|
updates, swap removal, and SSH hardening) and installs a pinned K3s server. It
|
||||||
|
is intentionally separate from the local k3d path so the portfolio can be
|
||||||
|
run without cloud credentials.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp inventory.example.yml inventory.yml
|
||||||
|
# Replace the Terraform public IP and local SSH key path.
|
||||||
|
ansible-playbook -i inventory.yml bootstrap-k3s.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Before production use, review the pinned K3s version and extend the playbook
|
||||||
|
for your organization’s OS baseline, firewall model, HA topology, and secret
|
||||||
|
management. RKE2 can replace K3s here if the target environment requires it.
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
- name: Harden host and install K3s
|
||||||
|
hosts: k3s_servers
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
k3s_version: "v1.30.6+k3s1"
|
||||||
|
k3s_install_url: "https://get.k3s.io"
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Require a supported Ubuntu release
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_distribution == "Ubuntu"
|
||||||
|
- ansible_distribution_version is version("22.04", ">=")
|
||||||
|
fail_msg: "This playbook expects Ubuntu 22.04 or newer."
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Install host security prerequisites
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- apparmor
|
||||||
|
- apparmor-utils
|
||||||
|
- curl
|
||||||
|
- ca-certificates
|
||||||
|
- unattended-upgrades
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Ensure unattended security upgrades are enabled
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: unattended-upgrades
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Disable swap for Kubernetes node
|
||||||
|
ansible.builtin.command: swapoff -a
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Remove swap entries from fstab
|
||||||
|
ansible.builtin.replace:
|
||||||
|
path: /etc/fstab
|
||||||
|
regexp: '^([^#].*\sswap\s+.*)$'
|
||||||
|
replace: '# Disabled for Kubernetes: \1'
|
||||||
|
|
||||||
|
- name: Set restrictive SSH password authentication
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/ssh/sshd_config.d/60-k8s-baseline.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
content: |
|
||||||
|
PasswordAuthentication no
|
||||||
|
PermitRootLogin no
|
||||||
|
notify: Restart ssh
|
||||||
|
|
||||||
|
- name: Install pinned K3s server
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
curl -sfL {{ k3s_install_url }} | INSTALL_K3S_VERSION={{ k3s_version }} sh -s - server --write-kubeconfig-mode 600
|
||||||
|
args:
|
||||||
|
creates: /usr/local/bin/k3s
|
||||||
|
|
||||||
|
- name: Enable and start K3s
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: k3s
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: Restart ssh
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: ssh
|
||||||
|
state: restarted
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
all:
|
||||||
|
children:
|
||||||
|
k3s_servers:
|
||||||
|
hosts:
|
||||||
|
k3s-1:
|
||||||
|
ansible_host: REPLACE_WITH_TERRAFORM_PUBLIC_IP
|
||||||
|
ansible_user: ubuntu
|
||||||
|
ansible_ssh_private_key_file: ~/.ssh/REPLACE_WITH_KEY
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# ArgoCD GitOps bootstrap
|
||||||
|
|
||||||
|
ArgoCD is installed once into the local cluster; everything after that is
|
||||||
|
declared through the root Application. The root uses the app-of-apps pattern:
|
||||||
|
it watches `argocd/apps/`, and each child Application owns one platform or
|
||||||
|
workload boundary.
|
||||||
|
|
||||||
|
## Bootstrap
|
||||||
|
|
||||||
|
1. Push this repository to GitHub and replace `REPLACE_WITH_GITHUB_OWNER` in
|
||||||
|
the Application manifests with the repository owner.
|
||||||
|
2. Create the local cluster from `local-quickstart/`.
|
||||||
|
3. Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl create namespace argocd --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
kubectl apply --server-side --force-conflicts -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
|
||||||
|
kubectl -n argocd rollout status deployment/argocd-server --timeout=180s
|
||||||
|
kubectl apply -f argocd/app-of-apps.yaml
|
||||||
|
kubectl get applications -n argocd -w
|
||||||
|
```
|
||||||
|
|
||||||
|
The first command is idempotent. The official install manifest is fetched at
|
||||||
|
bootstrap time rather than vendored into this repository, keeping the repo
|
||||||
|
reviewable and making the ArgoCD version choice visible in the command.
|
||||||
|
|
||||||
|
For local UI access:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n argocd port-forward svc/argocd-server 8081:443
|
||||||
|
kubectl -n argocd get secret argocd-initial-admin-secret \
|
||||||
|
-o jsonpath='{.data.password}' | base64 -d; echo
|
||||||
|
```
|
||||||
|
|
||||||
|
The initial admin secret is for local bootstrap only. A later hardening phase
|
||||||
|
should replace this with SSO/RBAC and remove the bootstrap credential.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: security-baseline-root
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: kubernetes-security-baseline
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
# Replace the owner after publishing this repository.
|
||||||
|
repoURL: https://github.com/REPLACE_WITH_GITHUB_OWNER/kubernetes-security-baseline.git
|
||||||
|
targetRevision: main
|
||||||
|
path: argocd/apps
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: argocd
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: falco
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
sources:
|
||||||
|
- repoURL: https://falcosecurity.github.io/charts
|
||||||
|
chart: falco
|
||||||
|
targetRevision: 4.21.1
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/falco/falco-values.yaml
|
||||||
|
- repoURL: https://github.com/REPLACE_WITH_GITHUB_OWNER/kubernetes-security-baseline.git
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: falco
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: kyverno
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-2"
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://kyverno.github.io/kyverno/
|
||||||
|
chart: kyverno
|
||||||
|
targetRevision: 3.3.7
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kyverno
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: security-policies
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
# Policies wait for Kyverno's CRDs/controller to exist.
|
||||||
|
argocd.argoproj.io/sync-wave: "0"
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://github.com/REPLACE_WITH_GITHUB_OWNER/kubernetes-security-baseline.git
|
||||||
|
targetRevision: main
|
||||||
|
path: policies/kyverno
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: security-baseline
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: security-test-workloads
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "1"
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://github.com/REPLACE_WITH_GITHUB_OWNER/kubernetes-security-baseline.git
|
||||||
|
targetRevision: main
|
||||||
|
path: test-workloads
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: security-baseline
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Phase 2 placeholder values. Runtime rules and webhook output are added in
|
||||||
|
# phase 5; keeping values in Git now establishes the ArgoCD ownership boundary.
|
||||||
|
falco:
|
||||||
|
json_output: true
|
||||||
|
json_include_output_property: true
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Local quick start
|
||||||
|
|
||||||
|
Prerequisites: Docker, `k3d`, and `kubectl`.
|
||||||
|
|
||||||
|
Create the cluster and verify all nodes become Ready:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
k3d cluster create --config local-quickstart/k3d-cluster-config.yaml
|
||||||
|
kubectl config use-context k3d-security-baseline
|
||||||
|
kubectl get nodes -o wide
|
||||||
|
```
|
||||||
|
|
||||||
|
The config creates one server and two agents and disables the bundled Traefik
|
||||||
|
so later GitOps components own the cluster add-ons explicitly.
|
||||||
|
|
||||||
|
To remove the local cluster:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
k3d cluster delete security-baseline
|
||||||
|
```
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
apiVersion: k3d.io/v1alpha5
|
||||||
|
kind: Simple
|
||||||
|
metadata:
|
||||||
|
name: security-baseline
|
||||||
|
|
||||||
|
# The default path is intentionally small enough for a laptop, while still
|
||||||
|
# exercising a server/agent topology rather than a single-node shortcut.
|
||||||
|
servers: 1
|
||||||
|
agents: 2
|
||||||
|
|
||||||
|
options:
|
||||||
|
k3s:
|
||||||
|
# Keep the local cluster focused on the security stack. Ingress can be
|
||||||
|
# added later without changing the cluster definition.
|
||||||
|
extraArgs:
|
||||||
|
- arg: --disable=traefik
|
||||||
|
nodeFilters:
|
||||||
|
- server:*
|
||||||
|
k3d:
|
||||||
|
wait: true
|
||||||
|
timeout: 120s
|
||||||
|
kubeconfig:
|
||||||
|
updateDefaultKubeconfig: true
|
||||||
|
switchCurrentContext: true
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- port: 8080:80
|
||||||
|
nodeFilters:
|
||||||
|
- loadbalancer
|
||||||
|
- port: 8443:443
|
||||||
|
nodeFilters:
|
||||||
|
- loadbalancer
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- phase-2-placeholder.yaml
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: security-baseline
|
||||||
|
labels:
|
||||||
|
security-baseline/open: "true"
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: policy-baseline-status
|
||||||
|
namespace: security-baseline
|
||||||
|
data:
|
||||||
|
phase: "2"
|
||||||
|
status: "GitOps target established; Kyverno policies arrive in phase 4"
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Optional production-style path
|
||||||
|
|
||||||
|
This directory provisions one encrypted Ubuntu EC2 host with a deliberately
|
||||||
|
small network surface. It is a scaffold for the documented cloud path; the
|
||||||
|
local k3d path remains the primary, cost-free portfolio demo.
|
||||||
|
|
||||||
|
The AWS account, region, AMI, SSH key pair, and administrator CIDR are inputs,
|
||||||
|
not repository values. Do not commit a real `terraform.tfvars` file or private
|
||||||
|
keys. The security group intentionally exposes SSH and the Kubernetes API only
|
||||||
|
to `admin_cidr`; add any public application ports explicitly when needed.
|
||||||
|
|
||||||
|
Example workflow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp terraform.tfvars.example terraform.tfvars
|
||||||
|
# Edit every replace-* value and set admin_cidr to your current IP /32.
|
||||||
|
terraform init
|
||||||
|
terraform validate
|
||||||
|
terraform plan
|
||||||
|
terraform apply
|
||||||
|
terraform output -raw public_ip
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run `ansible/bootstrap-k3s.yml` against the output IP. `terraform destroy`
|
||||||
|
removes the lab resources when finished. This path is not required for the
|
||||||
|
portfolio demo and is not invoked by CI.
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
data "aws_availability_zones" "available" {
|
||||||
|
state = "available"
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
availability_zone = coalesce(var.availability_zone, data.aws_availability_zones.available.names[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_vpc" "cluster" {
|
||||||
|
cidr_block = "10.42.0.0/16"
|
||||||
|
enable_dns_hostnames = true
|
||||||
|
enable_dns_support = true
|
||||||
|
|
||||||
|
tags = { Name = "k8s-security-baseline" }
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_subnet" "cluster" {
|
||||||
|
vpc_id = aws_vpc.cluster.id
|
||||||
|
cidr_block = "10.42.1.0/24"
|
||||||
|
availability_zone = local.availability_zone
|
||||||
|
|
||||||
|
tags = { Name = "k8s-security-baseline" }
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_internet_gateway" "cluster" {
|
||||||
|
vpc_id = aws_vpc.cluster.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route_table" "cluster" {
|
||||||
|
vpc_id = aws_vpc.cluster.id
|
||||||
|
|
||||||
|
route {
|
||||||
|
cidr_block = "0.0.0.0/0"
|
||||||
|
gateway_id = aws_internet_gateway.cluster.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route_table_association" "cluster" {
|
||||||
|
subnet_id = aws_subnet.cluster.id
|
||||||
|
route_table_id = aws_route_table.cluster.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "cluster" {
|
||||||
|
name = "k8s-security-baseline"
|
||||||
|
description = "Minimal access for the optional single-node K3s lab host"
|
||||||
|
vpc_id = aws_vpc.cluster.id
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
description = "SSH from the administrator CIDR"
|
||||||
|
from_port = 22
|
||||||
|
to_port = 22
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = [var.admin_cidr]
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
description = "Kubernetes API from the administrator CIDR"
|
||||||
|
from_port = 6443
|
||||||
|
to_port = 6443
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = [var.admin_cidr]
|
||||||
|
}
|
||||||
|
|
||||||
|
egress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "k3s" {
|
||||||
|
ami = var.ami_id
|
||||||
|
instance_type = var.instance_type
|
||||||
|
subnet_id = aws_subnet.cluster.id
|
||||||
|
vpc_security_group_ids = [aws_security_group.cluster.id]
|
||||||
|
key_name = var.ssh_key_name
|
||||||
|
associate_public_ip_address = true
|
||||||
|
|
||||||
|
root_block_device {
|
||||||
|
volume_size = 30
|
||||||
|
volume_type = "gp3"
|
||||||
|
encrypted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = { Name = "k8s-security-baseline" }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
output "public_ip" {
|
||||||
|
description = "Public IP to place in the Ansible inventory."
|
||||||
|
value = aws_instance.k3s.public_ip
|
||||||
|
}
|
||||||
|
|
||||||
|
output "ssh_command" {
|
||||||
|
description = "SSH command for initial connectivity testing."
|
||||||
|
value = "ssh ubuntu@${aws_instance.k3s.public_ip}"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
aws_region = "us-east-1"
|
||||||
|
availability_zone = null
|
||||||
|
instance_type = "t3.medium"
|
||||||
|
ssh_key_name = "replace-with-existing-key-pair"
|
||||||
|
admin_cidr = "203.0.113.10/32"
|
||||||
|
ami_id = "replace-with-ubuntu-22.04-ami-for-your-region"
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
variable "aws_region" {
|
||||||
|
description = "AWS region for the optional production-style K3s host."
|
||||||
|
type = string
|
||||||
|
default = "us-east-1"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "availability_zone" {
|
||||||
|
description = "Availability zone for the subnet. Leave null to use the first AZ."
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "instance_type" {
|
||||||
|
description = "EC2 instance type for the lab node."
|
||||||
|
type = string
|
||||||
|
default = "t3.medium"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ssh_key_name" {
|
||||||
|
description = "Existing EC2 key pair name used for Ansible bootstrap."
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "admin_cidr" {
|
||||||
|
description = "CIDR allowed to SSH to the node; restrict this to your admin IP."
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ami_id" {
|
||||||
|
description = "Ubuntu 22.04 LTS AMI ID for the selected region."
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
terraform {
|
||||||
|
required_version = ">= 1.6.0"
|
||||||
|
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
region = var.aws_region
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- phase-2-placeholder.yaml
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: test-workloads-status
|
||||||
|
namespace: security-baseline
|
||||||
|
data:
|
||||||
|
phase: "2"
|
||||||
|
status: "GitOps target established; security test workloads arrive in phase 6"
|
||||||
|
|
||||||
Reference in New Issue
Block a user