Skip to content

Commit 23d6060

Browse files
committed
feat: k8s service account
1 parent 9ca44ae commit 23d6060

File tree

9 files changed

+348
-0
lines changed

9 files changed

+348
-0
lines changed

modules/kubernetes/logo.png

493 KB
Loading
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Kubernetes Service Account
2+
3+
This building block creates a Kubernetes service account in your namespace with role-based access to cluster resources. Service accounts are used for automated authentication and authorization in CI/CD pipelines, applications, and automation scripts running within or outside the cluster.
4+
5+
## 🚀 Usage Examples
6+
7+
- A development team creates a service account to **automate deployments** from their CI/CD pipelines to Kubernetes resources.
8+
- A DevOps engineer sets up service accounts with **view access** for monitoring tools that need to observe cluster state.
9+
- A team configures a service account with **edit permissions** for their application to manage resources within their namespace.
10+
- An operations team uses the generated **kubeconfig** to configure external tools like ArgoCD or Flux.
11+
12+
## 🔄 Shared Responsibility
13+
14+
| Responsibility | Platform Team | Application Team |
15+
|----------------|---------------|------------------|
16+
| Create service account |||
17+
| Assign ClusterRole to service account |||
18+
| Provide kubeconfig credentials |||
19+
| Store kubeconfig securely |||
20+
| Use service account in pipelines/applications |||
21+
| Monitor service account usage |||
22+
| Use least privilege roles | ⚠️ ||
23+
| Request removal of unused service accounts |||
24+
25+
## 💡 Best Practices
26+
27+
### Service Account Naming
28+
29+
**Why**: Clear names help identify purpose and ownership.
30+
31+
**Recommended Patterns**:
32+
- Include application/service name: `myapp-production-sa`
33+
- Include purpose: `myapp-cicd-sa`, `myapp-monitoring-sa`
34+
- Include environment: `myapp-dev-sa`, `myapp-prod-sa`
35+
36+
**Examples**:
37+
-`ecommerce-prod-deployment-sa`
38+
-`analytics-monitoring-sa`
39+
-`backup-automation-sa`
40+
-`sa1`
41+
-`test-service-account`
42+
43+
### Role Selection
44+
45+
**Why**: Follow least privilege principle to minimize security risks.
46+
47+
| Role | Use Case |
48+
|------|----------|
49+
| `view` | Read-only access for monitoring, dashboards, debugging |
50+
| `edit` | Deploy and manage applications within namespace |
51+
| `admin` | Full namespace administration including RBAC |
52+
53+
**Recommendations**:
54+
- Start with `view` and escalate only if needed
55+
- Use `edit` for CI/CD pipelines that deploy applications
56+
- Reserve `admin` for tools that need to manage RBAC or other privileged resources
57+
58+
### Kubeconfig Management
59+
60+
**Why**: The kubeconfig contains sensitive credentials that grant access to your namespace.
61+
62+
**Best Practices**:
63+
- Store kubeconfig in a secure secrets manager (HashiCorp Vault, AWS Secrets Manager, etc.)
64+
- Never commit kubeconfig to version control
65+
- Rotate service account tokens periodically
66+
- Use short-lived tokens where possible
67+
68+
**Example Usage**:
69+
```bash
70+
# Save kubeconfig to a file
71+
echo "$KUBECONFIG_CONTENT" > kubeconfig
72+
73+
# Use with kubectl
74+
kubectl --kubeconfig kubeconfig get pods
75+
76+
# Or set KUBECONFIG environment variable
77+
export KUBECONFIG=./kubeconfig
78+
kubectl get pods
79+
```
80+
81+
### CI/CD Integration
82+
83+
**GitHub Actions Example**:
84+
```yaml
85+
steps:
86+
- name: Configure kubectl
87+
run: |
88+
echo "${{ secrets.KUBECONFIG }}" > kubeconfig
89+
kubectl --kubeconfig kubeconfig apply -f k8s/
90+
```
91+
92+
**GitLab CI Example**:
93+
```yaml
94+
deploy:
95+
script:
96+
- echo "$KUBECONFIG" > kubeconfig
97+
- kubectl --kubeconfig kubeconfig apply -f k8s/
98+
```
99+
100+
## ⚠️ Security Considerations
101+
102+
### Token Security
103+
104+
- The service account token provides **long-lived** access to the cluster
105+
- Anyone with the kubeconfig can access resources according to the assigned role
106+
- Treat the kubeconfig as a secret credential
107+
108+
### Namespace Isolation
109+
110+
- The role binding is **namespace-scoped**
111+
- The service account cannot access resources in other namespaces
112+
- Cross-namespace access requires additional configuration
113+
114+
### Audit and Monitoring
115+
116+
- All actions performed by the service account are **logged in Kubernetes audit logs**
117+
- Work with your platform team to set up **alerting** for suspicious activity
118+
- Regularly review service account usage and remove unused accounts
119+
120+
## 📋 Troubleshooting
121+
122+
### Common Issues
123+
124+
**"Forbidden" errors when using kubectl**:
125+
- Verify the assigned ClusterRole has the required permissions
126+
- Check if you're operating in the correct namespace
127+
- Ensure the kubeconfig context is set correctly
128+
129+
**Token not working**:
130+
- Verify the secret was created correctly
131+
- Check if the service account exists
132+
- Ensure the cluster CA certificate is correct
133+
134+
**Unable to connect to cluster**:
135+
- Verify the cluster endpoint is reachable from your network
136+
- Check firewall rules and network policies
137+
- Ensure the cluster CA certificate matches the cluster
138+
139+
### Getting Help
140+
141+
Contact your platform team if you:
142+
- Need elevated permissions beyond `edit`
143+
- Require access to cluster-wide resources
144+
- Experience persistent authentication issues
145+
- Need to rotate or regenerate credentials
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
name: Kubernetes Service Account
3+
supportedPlatforms:
4+
- kubernetes
5+
description: Creates a Kubernetes service account with ClusterRole binding and generates a kubeconfig for authentication
6+
---
7+
8+
# Kubernetes Service Account Building Block
9+
10+
Creates and manages a Kubernetes service account with role binding to a specified ClusterRole, and generates a kubeconfig file for authentication.
11+
12+
This documentation is intended as a reference for cloud foundation or platform engineers using this module.
13+
14+
## Prerequisites
15+
16+
- Access to a Kubernetes cluster
17+
- A service account with permissions to create service accounts, secrets, and role bindings
18+
- Cluster CA certificate (base64 encoded)
19+
- Token for the service account executing this module
20+
21+
## Features
22+
23+
- Creates a Kubernetes service account in a specified namespace
24+
- Creates a secret with service account token
25+
- Binds the service account to a specified ClusterRole (admin, edit, view, or custom)
26+
- Generates a ready-to-use kubeconfig file as output
27+
28+
> ⚠️ **Security Notice**: The `kubeconfig` output contains a service account token that grants access to the Kubernetes cluster. When displayed as plain text in meshStack, this sensitive credential will be visible to users who can view the building block outputs. Ensure that only authorized users have access to view these outputs, and advise users to store the kubeconfig securely after retrieval.
29+
30+
<!-- BEGIN_TF_DOCS -->
31+
## Requirements
32+
33+
| Name | Version |
34+
|------|---------|
35+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
36+
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | ~> 2.38 |
37+
38+
## Modules
39+
40+
No modules.
41+
42+
## Resources
43+
44+
| Name | Type |
45+
|------|------|
46+
| [kubernetes_role_binding.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/role_binding) | resource |
47+
| [kubernetes_secret.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
48+
| [kubernetes_service_account.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_account) | resource |
49+
50+
## Inputs
51+
52+
| Name | Description | Type | Default | Required |
53+
|------|-------------|------|---------|:--------:|
54+
| <a name="input_cluster_ca_certificate"></a> [cluster\_ca\_certificate](#input\_cluster\_ca\_certificate) | Cluster CA certificate, base64 encoded | `string` | n/a | yes |
55+
| <a name="input_cluster_endpoint"></a> [cluster\_endpoint](#input\_cluster\_endpoint) | IP address of the cluster control plane | `string` | n/a | yes |
56+
| <a name="input_cluster_name"></a> [cluster\_name](#input\_cluster\_name) | Name of the k8s cluster hosting this service account | `string` | n/a | yes |
57+
| <a name="input_cluster_role"></a> [cluster\_role](#input\_cluster\_role) | ClusterRole to bind the service account with. e.g. admin, edit, view (or any custom cluster role) | `string` | n/a | yes |
58+
| <a name="input_context"></a> [context](#input\_context) | Defines which cluster to interact with. Can be any name | `string` | n/a | yes |
59+
| <a name="input_name"></a> [name](#input\_name) | Service account name | `string` | n/a | yes |
60+
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Namespace where the service account will be created. Recommended: Use platform tenant ID as input in meshStack | `string` | n/a | yes |
61+
| <a name="input_token"></a> [token](#input\_token) | Token for the service account executing this module (not this service account) | `string` | n/a | yes |
62+
63+
## Outputs
64+
65+
| Name | Description |
66+
|------|-------------|
67+
| <a name="output_instructions"></a> [instructions](#output\_instructions) | Instructions for using the kubeconfig |
68+
| <a name="output_kubeconfig"></a> [kubeconfig](#output\_kubeconfig) | Kubeconfig file content for authenticating with the Kubernetes cluster |
69+
<!-- END_TF_DOCS -->
48 KB
Loading
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
resource "kubernetes_service_account" "this" {
2+
metadata {
3+
name = var.name
4+
namespace = var.namespace
5+
}
6+
}
7+
8+
resource "kubernetes_secret" "this" {
9+
metadata {
10+
name = kubernetes_service_account.this.metadata[0].name
11+
namespace = kubernetes_service_account.this.metadata[0].namespace
12+
annotations = {
13+
"kubernetes.io/service-account.name" = kubernetes_service_account.this.metadata[0].name
14+
}
15+
}
16+
17+
type = "kubernetes.io/service-account-token"
18+
}
19+
20+
resource "kubernetes_role_binding" "this" {
21+
metadata {
22+
name = "${var.name}-${var.cluster_role}"
23+
namespace = var.namespace
24+
}
25+
subject {
26+
kind = "ServiceAccount"
27+
name = var.name
28+
namespace = var.namespace
29+
}
30+
role_ref {
31+
api_group = "rbac.authorization.k8s.io"
32+
kind = "ClusterRole"
33+
name = var.cluster_role
34+
}
35+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
locals {
2+
kubeconfig = {
3+
apiVersion = "v1"
4+
kind = "Config"
5+
6+
users = [{
7+
name = kubernetes_service_account.this.metadata[0].name
8+
user = {
9+
token = kubernetes_secret.this.data["token"]
10+
}
11+
}]
12+
13+
clusters = [{
14+
cluster = {
15+
certificate-authority-data = var.cluster_ca_certificate
16+
server = "https://${var.cluster_endpoint}"
17+
}
18+
name = var.cluster_name
19+
}
20+
]
21+
22+
contexts = [{
23+
context = {
24+
cluster = var.cluster_name
25+
namespace = var.namespace
26+
user = kubernetes_service_account.this.metadata[0].name
27+
}
28+
name = var.context
29+
}]
30+
31+
current-context = var.context
32+
}
33+
}
34+
35+
output "instructions" {
36+
description = "Instructions for using the kubeconfig"
37+
value = "Copy kubeconfig value into a file, which can be directly used. e.g. `kubectl --kubeconfig kubeconfig get pods`"
38+
}
39+
40+
output "kubeconfig" {
41+
description = "Kubeconfig file content for authenticating with the Kubernetes cluster"
42+
sensitive = true
43+
value = yamlencode(local.kubeconfig)
44+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
provider "kubernetes" {
2+
host = "https://${var.cluster_endpoint}"
3+
cluster_ca_certificate = base64decode(var.cluster_ca_certificate)
4+
token = var.token
5+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
variable "name" {
2+
type = string
3+
description = "Service account name"
4+
}
5+
6+
variable "namespace" {
7+
type = string
8+
description = "Namespace where the service account will be created. Recommended: Use platform tenant ID as input in meshStack"
9+
}
10+
11+
variable "cluster_name" {
12+
type = string
13+
description = "Name of the k8s cluster hosting this service account"
14+
}
15+
16+
variable "cluster_endpoint" {
17+
type = string
18+
description = "IP address of the cluster control plane"
19+
}
20+
21+
variable "cluster_ca_certificate" {
22+
type = string
23+
description = "Cluster CA certificate, base64 encoded"
24+
}
25+
26+
variable "context" {
27+
type = string
28+
description = "Defines which cluster to interact with. Can be any name"
29+
}
30+
31+
variable "cluster_role" {
32+
type = string
33+
description = "ClusterRole to bind the service account with. e.g. admin, edit, view (or any custom cluster role)"
34+
}
35+
36+
variable "token" {
37+
type = string
38+
sensitive = true
39+
description = "Token for the service account executing this module (not this service account)"
40+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
kubernetes = {
6+
source = "hashicorp/kubernetes"
7+
version = "~> 2.38"
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)