11import os
2+ import sys
23from pathlib import Path
34
45import click
6+ import yaml
57from rich import print as richprint
68
7- from .constants import NETWORK_DIR
9+ from .constants import KUBECONFIG , NETWORK_DIR , WARGAMES_NAMESPACE_PREFIX
10+ from .k8s import (
11+ K8sError ,
12+ get_cluster_of_current_context ,
13+ get_namespaces_by_type ,
14+ get_service_accounts_in_namespace ,
15+ open_kubeconfig ,
16+ )
817from .namespaces import copy_namespaces_defaults , namespaces
918from .network import copy_network_defaults
19+ from .process import run_command
1020
1121
1222@click .group (name = "admin" , hidden = True )
@@ -33,3 +43,94 @@ def init():
3343 f"[green]Copied network and namespace example files to { Path (current_dir ) / NETWORK_DIR .name } [/green]"
3444 )
3545 richprint (f"[green]Created warnet project structure in { current_dir } [/green]" )
46+
47+
48+ @admin .command ()
49+ @click .option (
50+ "--kubeconfig-dir" ,
51+ default = "kubeconfigs" ,
52+ help = "Directory to store kubeconfig files (default: kubeconfigs)" ,
53+ )
54+ @click .option (
55+ "--token-duration" ,
56+ default = 172800 ,
57+ type = int ,
58+ help = "Duration of the token in seconds (default: 48 hours)" ,
59+ )
60+ def create_kubeconfigs (kubeconfig_dir , token_duration ):
61+ """Create kubeconfig files for ServiceAccounts"""
62+ kubeconfig_dir = os .path .expanduser (kubeconfig_dir )
63+
64+ try :
65+ kubeconfig_data = open_kubeconfig (KUBECONFIG )
66+ except K8sError as e :
67+ click .secho (e , fg = "yellow" )
68+ click .secho (f"Could not open auth_config: { KUBECONFIG } " , fg = "red" )
69+ sys .exit (1 )
70+
71+ cluster = get_cluster_of_current_context (kubeconfig_data )
72+
73+ os .makedirs (kubeconfig_dir , exist_ok = True )
74+
75+ # Get all namespaces that start with prefix
76+ # This assumes when deploying multiple namespaces for the purpose of team games, all namespaces start with a prefix,
77+ # e.g., tabconf-wargames-*. Currently, this is a bit brittle, but we can improve on this in the future
78+ # by automatically applying a TEAM_PREFIX when creating the get_warnet_namespaces
79+ # TODO: choose a prefix convention and have it managed by the helm charts instead of requiring the
80+ # admin user to pipe through the correct string in multiple places. Another would be to use
81+ # labels instead of namespace naming conventions
82+ warnet_namespaces = get_namespaces_by_type (WARGAMES_NAMESPACE_PREFIX )
83+
84+ for v1namespace in warnet_namespaces :
85+ namespace = v1namespace .metadata .name
86+ click .echo (f"Processing namespace: { namespace } " )
87+ service_accounts = get_service_accounts_in_namespace (namespace )
88+
89+ for sa in service_accounts :
90+ # Create a token for the ServiceAccount with specified duration
91+ command = f"kubectl create token { sa } -n { namespace } --duration={ token_duration } s"
92+ try :
93+ token = run_command (command )
94+ except Exception as e :
95+ click .echo (
96+ f"Failed to create token for ServiceAccount { sa } in namespace { namespace } . Error: { str (e )} . Skipping..."
97+ )
98+ continue
99+
100+ # Create a kubeconfig file for the user
101+ kubeconfig_file = os .path .join (kubeconfig_dir , f"{ sa } -{ namespace } -kubeconfig" )
102+
103+ # TODO: move yaml out of python code to resources/manifests/
104+ #
105+ # might not be worth it since we are just reading the yaml to then create a bunch of values and its not
106+ # actually used to deploy anything into the cluster
107+ # Then benefit would be making this code a bit cleaner and easy to follow, fwiw
108+ kubeconfig_dict = {
109+ "apiVersion" : "v1" ,
110+ "kind" : "Config" ,
111+ "clusters" : [cluster ],
112+ "users" : [{"name" : sa , "user" : {"token" : token }}],
113+ "contexts" : [
114+ {
115+ "name" : f"{ sa } -{ namespace } " ,
116+ "context" : {"cluster" : cluster ["name" ], "namespace" : namespace , "user" : sa },
117+ }
118+ ],
119+ "current-context" : f"{ sa } -{ namespace } " ,
120+ }
121+
122+ # Write to a YAML file
123+ with open (kubeconfig_file , "w" ) as f :
124+ yaml .dump (kubeconfig_dict , f , default_flow_style = False )
125+
126+ click .echo (f" Created kubeconfig file for { sa } : { kubeconfig_file } " )
127+
128+ click .echo ("---" )
129+ click .echo (
130+ f"All kubeconfig files have been created in the '{ kubeconfig_dir } ' directory with a duration of { token_duration } seconds."
131+ )
132+ click .echo ("Distribute these files to the respective users." )
133+ click .echo (
134+ "Users can then use by running `warnet auth <file>` or with kubectl by specifying the --kubeconfig flag or by setting the KUBECONFIG environment variable."
135+ )
136+ click .echo (f"Note: The tokens will expire after { token_duration } seconds." )
0 commit comments