Skip to content

add create-kubeconfigs command #545

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

Closed
Closed
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
26 changes: 25 additions & 1 deletion resources/charts/namespaces/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,32 @@ roles:
- 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", "update", "delete"]
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"]
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ roles:
- name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods"]
resources: ["pods", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
52 changes: 50 additions & 2 deletions resources/namespaces/two_namespaces_two_users/namespaces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,35 @@ namespaces:
- 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", "update", "delete"]
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
users:
- name: mallory
Expand All @@ -34,8 +58,32 @@ namespaces:
- 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", "update", "delete"]
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"]
132 changes: 132 additions & 0 deletions src/warnet/admin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import subprocess # TODO: use run_command or similar; NOT subprocess
from pathlib import Path

import click
Expand Down Expand Up @@ -33,3 +34,134 @@ 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]")


# Get kubectl values
def get_kubectl_value(jsonpath):
return subprocess.check_output(
["kubectl", "config", "view", "--minify", "-o", f"jsonpath={jsonpath}"]
).decode("utf-8")


# Get all namespaces that start with "warnet-"
def get_warnet_namespaces():
Copy link
Collaborator

Choose a reason for hiding this comment

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

if we are going to start having conventions around namespace strings (e.g., warnet-), might be more useful to make this a "get_namespaces_by_prefix(prefix: str)" function. not urgent, though

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @josibake but more strongly. I think we should avoid using any naming conventions like we did before helm (if possible) -- can we use kubernetes metadata "labels" instead?

# TODO: paramaterize with prefix
namespaces = (
subprocess.check_output(
["kubectl", "get", "namespaces", "-o", "jsonpath={.items[*].metadata.name}"]
)
.decode("utf-8")
.split()
)
return [ns for ns in namespaces if ns.startswith("warnet-")]


# Get all service accounts for a given namespace
def get_service_accounts(namespace):
return (
subprocess.check_output(
[
"kubectl",
"get",
"serviceaccounts",
"-n",
namespace,
"-o",
"jsonpath={.items[*].metadata.name}",
]
)
.decode("utf-8")
.split()
)


@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 all ServiceAccounts in namespaces starting with 'warnet-'."""
kubeconfig_dir = os.path.expanduser(kubeconfig_dir)

cluster_name = get_kubectl_value("{.clusters[0].name}")
cluster_server = get_kubectl_value("{.clusters[0].cluster.server}")
cluster_ca = get_kubectl_value("{.clusters[0].cluster.certificate-authority-data}")

os.makedirs(kubeconfig_dir, exist_ok=True)

# Get all namespaces that start with "warnet-"
warnet_namespaces = get_warnet_namespaces()

for namespace in warnet_namespaces:
click.echo(f"Processing namespace: {namespace}")
service_accounts = get_service_accounts(namespace)

for sa in service_accounts:
click.echo(f"Processing ServiceAccount: {sa}")

# Create a token for the ServiceAccount with specified duration
try:
token = (
subprocess.check_output(
[
"kubectl",
"create",
"token",
sa,
"-n",
namespace,
f"--duration={token_duration}s",
]
)
.decode("utf-8")
.strip()
)
except subprocess.CalledProcessError:
click.echo(f"Failed to create token for ServiceAccount {sa}. 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
kubeconfig_content = f"""apiVersion: v1
Copy link
Collaborator

Choose a reason for hiding this comment

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

works for now, but ideally we keep the k8s yamls out of the python code. maybe just leave a #TODO comment to move this at some point ?

kind: Config
clusters:
- name: {cluster_name}
cluster:
server: {cluster_server}
certificate-authority-data: {cluster_ca}
users:
- name: {sa}
user:
token: {token}
contexts:
- name: {sa}-{namespace}
context:
cluster: {cluster_name}
namespace: {namespace}
user: {sa}
current-context: {sa}-{namespace}
"""
with open(kubeconfig_file, "w") as f:
f.write(kubeconfig_content)

click.echo(f"Created kubeconfig file for {sa}: {kubeconfig_file}")
click.echo(f"Token duration: {token_duration} seconds")
click.echo(f"To use this config, run: kubectl --kubeconfig={kubeconfig_file} get pods")
click.echo("---")

click.echo(f"All kubeconfig files have been created in the '{kubeconfig_dir}' directory.")
click.echo("Distribute these files to the respective users.")
click.echo(
"Users can then use them 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.")