Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using team namespaces: Kubeconfig Step Thru #616

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
56bc1c3
constants: make the default namespace "default"
mplsgrant Sep 27, 2024
c848848
constants: add `wargames` prefix
mplsgrant Sep 27, 2024
39db0b5
constants: add k8s internal namespaces
mplsgrant Sep 27, 2024
4683dc9
refactor: namespaces.yaml, namespace-defaults.yaml
josibake Sep 13, 2024
305c189
charts: allow users access to services
mplsgrant Sep 24, 2024
61cff4a
charts: add namespace to sa permissions
mplsgrant Sep 27, 2024
f34113a
deploy: allow a namespace parameter in `deploy`
josibake Sep 13, 2024
bb0e9cb
admin: add create_kubeconfigs func
mplsgrant Oct 1, 2024
542f38a
service_accounts: add sa func to admin section
mplsgrant Oct 1, 2024
4518cc6
namespaces: remove the dir from the `namespaces`
mplsgrant Sep 24, 2024
714eff0
namespaces: flesh out wargames prefix
mplsgrant Sep 30, 2024
2bcf737
status: add namespace to `status`
mplsgrant Sep 27, 2024
527e583
workflow: add test to git workflow
mplsgrant Sep 30, 2024
997ca62
k8s: add ns, sa, and config helper funcs
mplsgrant Oct 1, 2024
fc77971
k8s: fix static_client type
mplsgrant Sep 27, 2024
ab42fc3
k8s: update getting namespace logic
mplsgrant Sep 27, 2024
0a2bd1a
k8s: ignore internal namespaces
mplsgrant Sep 27, 2024
ffdfec2
k8s & control: query all namespaces
mplsgrant Oct 1, 2024
b9ebff9
k8s: add optional ns to get_pod_exit_stats
mplsgrant Oct 1, 2024
a22cea8
k8s: add optional ns to delete_pod
mplsgrant Oct 1, 2024
e2aeecd
k8s: add optional ns to get_edges
mplsgrant Oct 1, 2024
1a25418
k8s: add optional ns to snapshot_bitcoin_datadir
mplsgrant Oct 1, 2024
ac11388
k8s: add optional ns to wait_for_init
mplsgrant Oct 1, 2024
9c0f82c
k8s: add optional ns to pod_log
mplsgrant Oct 1, 2024
f1d8d5c
k8s: add optional ns to wait_for_pod
mplsgrant Oct 1, 2024
1593cfe
k8s: add optional ns to write_file_to_container
mplsgrant Oct 1, 2024
402ee83
k8s: add namespace to `wait_for_init`
mplsgrant Oct 1, 2024
1ecdcdf
network: add namespace to `network` `_connected`
mplsgrant Oct 1, 2024
6242838
control: use namespace log in `down`
mplsgrant Sep 27, 2024
76897d3
control & test base: prevent hasty `down`s
mplsgrant Sep 27, 2024
159ac61
control: clean up `down` command
mplsgrant Oct 1, 2024
9da42aa
control: add ns to `logs`
mplsgrant Oct 1, 2024
cd00478
control: add namespace to `run`
mplsgrant Oct 1, 2024
a05e0c7
control: add imports
mplsgrant Oct 1, 2024
f0b2d4b
control: ignore logging namespaces
mplsgrant Oct 1, 2024
5100b0a
bitcoin: add ns to `rpc`
mplsgrant Oct 1, 2024
59913cd
bitcoin: add ns to `debug_log` and `grep_logs`
mplsgrant Oct 1, 2024
c94c7a3
bitcoin: add ns to `messages` and `get_messages`
mplsgrant Oct 1, 2024
7acf45d
deploy: enable deploying to all user namespaces
mplsgrant Oct 2, 2024
ea1827c
test base: add namespace to get_pod_exit_status
mplsgrant Oct 1, 2024
8b6e9da
testing: add e2e namespace/admin test
mplsgrant Sep 30, 2024
3f91d0b
admin.md: add admin documentation
mplsgrant Sep 24, 2024
e1c277c
k8s: add `continue` to `wait_for_init`
mplsgrant Oct 1, 2024
2c15b6c
testing: remove mention of minikube
mplsgrant Oct 3, 2024
6709805
tesing: use a temporary directory
mplsgrant Oct 3, 2024
70a736f
admin: update create_kubeconfig description
mplsgrant Oct 3, 2024
809eb5c
admin: spelling nit
mplsgrant Oct 3, 2024
1feed7a
DRY out the namespace check
mplsgrant Oct 3, 2024
e40ea68
testing: finish replacing minikube logic
mplsgrant Oct 3, 2024
d47073c
ruff get_default_namespace_or
mplsgrant Oct 3, 2024
e208c0e
testing: bring service account checking "in house"
mplsgrant Oct 3, 2024
7135973
service_accounts: remove func from `admin` section
mplsgrant Oct 3, 2024
30af65a
admin: make kubeconfig a dict
mplsgrant Oct 3, 2024
5188108
constants: use labels to select pods for `log`
mplsgrant Oct 3, 2024
2bb87ec
rename to `get_namespaces_by_type`
mplsgrant Oct 3, 2024
2cf8292
k8s: add `can_delete_pods` function
mplsgrant Oct 3, 2024
d6f4ed3
control: update `down` with `can_delete_pods`
mplsgrant Oct 3, 2024
bfc778b
admin.md: update namespace deploy command
mplsgrant Oct 3, 2024
ae19f28
bitcoin: make ruff happy
mplsgrant Oct 3, 2024
e7dbaf1
k8s: add open/write kubeconfig fn; add K8sError
mplsgrant Oct 4, 2024
5a38e92
constants: remove --create-namespace
mplsgrant Oct 4, 2024
7320758
testing: specify `warnettest` in named items
mplsgrant Oct 4, 2024
4876415
testing: update test to include cleanup
mplsgrant Oct 4, 2024
971afb9
constants: does graph_test.py need --create-namespace?
mplsgrant Oct 4, 2024
506bd58
k8s: get raw config values from kubectl
mplsgrant Oct 4, 2024
02cf9e5
k8s: get cluster from current context
mplsgrant Oct 4, 2024
a9239a7
auth: update auth func to avoid flattening
mplsgrant Oct 4, 2024
ed5fb00
admin: get raw cluster for auth file
mplsgrant Oct 4, 2024
6ecc017
bitcoin: update `message` to take tank-a.namespace
mplsgrant Oct 4, 2024
21815f0
deploy: fix override path
mplsgrant Oct 7, 2024
1024bcf
`admin.md`: reword deploy documentation
mplsgrant Oct 7, 2024
8024236
removing --create-namespace from constants
m3dwards Oct 7, 2024
82cf687
removing --create-namespace from constants
m3dwards Oct 7, 2024
d9b3e1d
gitignore: add kubeconfigs dir
mplsgrant Oct 7, 2024
6f18eb8
k8s: use mv to prevent scenario getting cut off
mplsgrant Oct 7, 2024
424eba8
k8s: add `sync` to make sure the data is written
mplsgrant Oct 7, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ jobs:
- services_test.py
- signet_test.py
- scenarios_test.py
- namespace_admin_test.py
steps:
- uses: actions/checkout@v4
- uses: azure/setup-helm@v4.2.0
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ warnet.egg-info
.env
dist/
build/
**/kubeconfigs/
69 changes: 69 additions & 0 deletions docs/admin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Admin

## Connect to your cluster

Ensure you are connected to your cluster because Warnet will use your current configuration to generate configurations for your users.

```shell
$ warnet status
```

Observe that the output of the command matches your cluster.

## Create an *admin* directory

```shell
$ mkdir admin
$ cd admin
$ warnet admin init
```

Observe that there are now two folders within the *admin* directory: *namespaces* and *networks*

## The *namespaces* directory
This directory contains a Helm chart named *two_namespaces_two_users*.

Modify this chart based on the number of teams and users you have.

Deploy the *two_namespaces_two_users* chart.

```shell
$ warnet deploy namespaces/two_namespaces_two_users
```

Observe that this creates service accounts and namespaces in the cluster:

```shell
$ kubectl get ns
$ kubectl get sa -A
```

### Creating Warnet invites
A Warnet invite is a Kubernetes config file.

Create invites for each of your users.

```shell
$ warnet admin create-kubeconfigs
```

Observe the *kubeconfigs* directory. It holds invites for each user.

### Using Warnet invites
Users can connect to your wargame using their invite.

```shell
$ warnet auth alice-wargames-red-team-kubeconfig
```

### Set up a network for your users
Before letting the users into your cluster, make sure to create a network of tanks for them to view.


```shell
$ warnet deploy networks/mynet --to-all-users
```

Observe that the *wargames-red-team* namespace now has tanks in it.

**TODO**: What's the logging approach here?
12 changes: 6 additions & 6 deletions resources/charts/namespaces/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@ roles:
- name: pod-viewer
rules:
- apiGroups: [""]
resources: ["pods"]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
verbs: ["get"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
resources: ["persistentvolumeclaims", "namespaces"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get"]
- name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods"]
resources: ["pods", "services"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
verbs: ["get", "create"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "create"]
verbs: ["get", "list", "create"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
resources: ["persistentvolumeclaims", "namespaces"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ users:
roles:
- pod-viewer
- pod-manager
roles:
- name: pod-viewer
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
# the pod-viewer and pod-manager roles are the default
# roles defined in values.yaml for the namespaces charts
#
# if you need a different set of roles for a particular namespaces
# deployment, you can override values.yaml by providing your own
# role definitions below
#
# roles:
# - name: my-custom-role
# rules:
# - apiGroups: ""
# resources: ""
# verbs: ""
74 changes: 2 additions & 72 deletions resources/namespaces/two_namespaces_two_users/namespaces.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespaces:
- name: warnet-red-team
- name: wargames-red-team
users:
- name: alice
roles:
Expand All @@ -8,42 +8,7 @@ namespaces:
roles:
- pod-viewer
- pod-manager
roles:
- name: pod-viewer
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
verbs: ["get"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get"]
- name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
verbs: ["get", "create"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "create"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get"]
- name: warnet-blue-team
- name: wargames-blue-team
users:
- name: mallory
roles:
Expand All @@ -52,38 +17,3 @@ namespaces:
roles:
- pod-viewer
- pod-manager
roles:
- name: pod-viewer
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
verbs: ["get"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get"]
- name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/attach", "pods/portforward"]
verbs: ["get", "create"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "create"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get"]
103 changes: 102 additions & 1 deletion src/warnet/admin.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import os
import sys
from pathlib import Path

import click
import yaml
from rich import print as richprint

from .constants import NETWORK_DIR
from .constants import KUBECONFIG, NETWORK_DIR, WARGAMES_NAMESPACE_PREFIX
from .k8s import (
K8sError,
get_cluster_of_current_context,
get_namespaces_by_type,
get_service_accounts_in_namespace,
open_kubeconfig,
)
from .namespaces import copy_namespaces_defaults, namespaces
from .network import copy_network_defaults
from .process import run_command


@click.group(name="admin", hidden=True)
Expand All @@ -33,3 +43,94 @@ def init():
f"[green]Copied network and namespace example files to {Path(current_dir) / NETWORK_DIR.name}[/green]"
)
richprint(f"[green]Created warnet project structure in {current_dir}[/green]")


@admin.command()
@click.option(
"--kubeconfig-dir",
default="kubeconfigs",
help="Directory to store kubeconfig files (default: kubeconfigs)",
)
@click.option(
"--token-duration",
default=172800,
type=int,
help="Duration of the token in seconds (default: 48 hours)",
)
def create_kubeconfigs(kubeconfig_dir, token_duration):
"""Create kubeconfig files for ServiceAccounts"""
kubeconfig_dir = os.path.expanduser(kubeconfig_dir)

try:
kubeconfig_data = open_kubeconfig(KUBECONFIG)
except K8sError as e:
click.secho(e, fg="yellow")
click.secho(f"Could not open auth_config: {KUBECONFIG}", fg="red")
sys.exit(1)

cluster = get_cluster_of_current_context(kubeconfig_data)

os.makedirs(kubeconfig_dir, exist_ok=True)

# Get all namespaces that start with prefix
# This assumes when deploying multiple namespaces for the purpose of team games, all namespaces start with a prefix,
# e.g., tabconf-wargames-*. Currently, this is a bit brittle, but we can improve on this in the future
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still pretty worried about the tech debt from this mechanism since it is so ubiquitous in this PR. Hard-coding the k8s namespaces and logging namesapce as well... and forcing the user to use a naming convention... all seems to go against our design principles!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that the prefixes is an anti pattern. I was looking at using namespace labels so they we could do things like get_namespaces_by_type(WARNET_TANKS) / get_namespaces_by_type(LOGGING) / get_namespaces_by_type(ALL), etc but that felt like it would take more work to get right. If the tradeoff is we have prefixed namespaces and can use namespaces for Tabconf, vs we don't have namespaces for Tabconf at all, I'm more inclined to proceed as is and have a backlog to refactor to using labels (happy to own following up on that).

# by automatically applying a TEAM_PREFIX when creating the get_warnet_namespaces
# TODO: choose a prefix convention and have it managed by the helm charts instead of requiring the
# admin user to pipe through the correct string in multiple places. Another would be to use
# labels instead of namespace naming conventions
warnet_namespaces = get_namespaces_by_type(WARGAMES_NAMESPACE_PREFIX)

for v1namespace in warnet_namespaces:
namespace = v1namespace.metadata.name
click.echo(f"Processing namespace: {namespace}")
service_accounts = get_service_accounts_in_namespace(namespace)

for sa in service_accounts:
# Create a token for the ServiceAccount with specified duration
command = f"kubectl create token {sa} -n {namespace} --duration={token_duration}s"
try:
token = run_command(command)
except Exception as e:
click.echo(
f"Failed to create token for ServiceAccount {sa} in namespace {namespace}. Error: {str(e)}. Skipping..."
)
continue

# Create a kubeconfig file for the user
kubeconfig_file = os.path.join(kubeconfig_dir, f"{sa}-{namespace}-kubeconfig")

# TODO: move yaml out of python code to resources/manifests/
#
# might not be worth it since we are just reading the yaml to then create a bunch of values and its not
# actually used to deploy anything into the cluster
# Then benefit would be making this code a bit cleaner and easy to follow, fwiw
kubeconfig_dict = {
"apiVersion": "v1",
"kind": "Config",
"clusters": [cluster],
"users": [{"name": sa, "user": {"token": token}}],
"contexts": [
{
"name": f"{sa}-{namespace}",
"context": {"cluster": cluster["name"], "namespace": namespace, "user": sa},
}
],
"current-context": f"{sa}-{namespace}",
}

# Write to a YAML file
with open(kubeconfig_file, "w") as f:
yaml.dump(kubeconfig_dict, f, default_flow_style=False)

click.echo(f" Created kubeconfig file for {sa}: {kubeconfig_file}")

click.echo("---")
click.echo(
f"All kubeconfig files have been created in the '{kubeconfig_dir}' directory with a duration of {token_duration} seconds."
)
click.echo("Distribute these files to the respective users.")
click.echo(
"Users can then use by running `warnet auth <file>` or with kubectl by specifying the --kubeconfig flag or by setting the KUBECONFIG environment variable."
)
click.echo(f"Note: The tokens will expire after {token_duration} seconds.")
Loading