Initial Commit
This commit is contained in:
commit
0cb818404a
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.linting.enabled": true
|
||||
}
|
34
README.md
Normal file
34
README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# kcf - kubectl fetcher
|
||||
|
||||
A small python script to merge a remote kubectl config with a local stored
|
||||
configuration file. It supports cli flags. The following
|
||||
|
||||
```bash
|
||||
$ ./main.py -h
|
||||
usage: main.py [-h] --host HOSTNAME [--port PORT] [--username USERNAME] [--password PASSWORD] [--identity-file IDENTITY_FILE] [--identity-passphrase IDENTITY_PASSPHRASE]
|
||||
[--remote-config REMOTE_CONFIG] [--remove-cluster-name REMOTE_CLUSTER_NAME] [--remove-user-name REMOTE_USER_NAME] [--local-config LOCAL_CONFIG]
|
||||
[--local-cluster-name LOCAL_CLUSTER_NAME] [--local-user-name LOCAL_USER_NAME]
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--host HOSTNAME SSH-Server
|
||||
--port PORT SSH-Port
|
||||
--username USERNAME Remote Unix User
|
||||
--password PASSWORD Remote password
|
||||
--identity-file IDENTITY_FILE
|
||||
Path to private SSH-Key
|
||||
--identity-passphrase IDENTITY_PASSPHRASE
|
||||
Passphrase of the SSH-Key
|
||||
--remote-config REMOTE_CONFIG
|
||||
Remote kubectl config
|
||||
--remove-cluster-name REMOTE_CLUSTER_NAME
|
||||
Name of the cluster
|
||||
--remove-user-name REMOTE_USER_NAME
|
||||
Name of the user
|
||||
--local-config LOCAL_CONFIG
|
||||
Local kubectl config
|
||||
--local-cluster-name LOCAL_CLUSTER_NAME
|
||||
Name of the cluster
|
||||
--local-user-name LOCAL_USER_NAME
|
||||
Name of the user
|
||||
```
|
117
main.py
Executable file
117
main.py
Executable file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import paramiko
|
||||
import os
|
||||
import yaml
|
||||
from yaml.loader import SafeLoader
|
||||
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519, dsa, rsa, ec
|
||||
from io import StringIO
|
||||
from scp import SCPClient
|
||||
from paramiko import RSAKey, Ed25519Key, ECDSAKey, DSSKey, PKey, SSHClient
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--host", dest="hostname", required=True, type=str, help="SSH-Server")
|
||||
parser.add_argument("--port", dest="port", default=22, type=int, help="SSH-Port")
|
||||
parser.add_argument("--username", dest="username", default=os.getlogin(), type=str, help="Remote Unix User")
|
||||
parser.add_argument("--password", dest="password", default=None, type=str, help="Remote password")
|
||||
parser.add_argument("--identity-file", dest="identity_file", default=None, type=str, help="Path to private SSH-Key")
|
||||
parser.add_argument("--identity-passphrase", dest="identity_passphrase", default=None, type=str, help="Passphrase of the SSH-Key")
|
||||
parser.add_argument("--remote-config", dest="remote_config", default="~/.kube/config", type=str, help="Remote kubectl config")
|
||||
parser.add_argument("--remove-cluster-name", dest="remote_cluster_name", default="kubernetes", type=str, help="Name of the cluster")
|
||||
parser.add_argument("--remove-user-name", dest="remote_user_name", default="kubernetes-admin", type=str, help="Name of the user")
|
||||
parser.add_argument("--local-config", dest="local_config", default="~/.kube/config", type=str, help="Local kubectl config")
|
||||
parser.add_argument("--local-cluster-name", dest="local_cluster_name", default="kubernetes", type=str, help="Name of the cluster")
|
||||
parser.add_argument("--local-user-name", dest="local_user_name", default="kubernetes-admin", type=str, help="Name of the user")
|
||||
args = parser.parse_args()
|
||||
|
||||
ssh_client = create_ssh_client(args.hostname, args.port, args.username, args.identity_file, args.identity_passphrase)
|
||||
scp_client = SCPClient(ssh_client.get_transport())
|
||||
|
||||
scp_client.get(args.remote_config, local_path="/tmp/admin.config")
|
||||
|
||||
with open("/tmp/admin.config", 'r', encoding="UTF-8") as f:
|
||||
remote_config = yaml.load(f, Loader=SafeLoader)
|
||||
|
||||
with open(args.local_config, 'r', encoding="UTF-8") as f:
|
||||
local_config = yaml.load(f, Loader=SafeLoader)
|
||||
|
||||
|
||||
# Remove old objects
|
||||
local_config["clusters"] = list(filter(lambda cluster: cluster["name"] != args.local_cluster_name, local_config["clusters"]))
|
||||
local_config["users"] = list(filter(lambda user: user["name"] != args.local_user_name, local_config["users"]))
|
||||
|
||||
# Add new objects
|
||||
local_config["clusters"] = local_config["clusters"] + list(filter(lambda cluster: cluster["name"] == args.remote_cluster_name, remote_config["clusters"]))
|
||||
local_config["users"] = local_config["users"] + list(filter(lambda user: user["name"] == args.remote_user_name, remote_config["users"]))
|
||||
|
||||
# Rename object attributes
|
||||
for cluster in list(filter(lambda cluster: cluster["name"] == args.remote_cluster_name, remote_config["clusters"])):
|
||||
cluster["name"] = args.local_cluster_name
|
||||
|
||||
for user in list(filter(lambda user: user["name"] == args.remote_user_name, remote_config["users"])):
|
||||
user["name"] = args.local_user_name
|
||||
|
||||
# Store new local_config
|
||||
with open(args.local_config, 'w', encoding="UTF-8") as f:
|
||||
yaml.dump(local_config, f)
|
||||
|
||||
def create_ssh_client(hostname: str, port: str, username: str, identity_file: str, identity_passphrase: str) -> SSHClient:
|
||||
ssh_client = paramiko.SSHClient()
|
||||
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
ssh_private_key = PKey
|
||||
|
||||
if identity_file != None and os.path.isfile(identity_file):
|
||||
ssh_private_key_file_obj = open(file=identity_file, mode="r", encoding="UTF-8")
|
||||
ssh_private_key = from_private_key(ssh_private_key_file_obj, identity_passphrase)
|
||||
|
||||
ssh_client.connect(username=username, hostname = hostname, port = port, pkey=ssh_private_key, compress=True)
|
||||
|
||||
return ssh_client
|
||||
|
||||
|
||||
def from_private_key(file_obj, password=None) -> PKey:
|
||||
private_key = None
|
||||
file_bytes = bytes(file_obj.read(), "utf-8")
|
||||
try:
|
||||
key = crypto_serialization.load_ssh_private_key(
|
||||
file_bytes,
|
||||
password=password,
|
||||
)
|
||||
file_obj.seek(0)
|
||||
except ValueError:
|
||||
key = crypto_serialization.load_pem_private_key(
|
||||
file_bytes,
|
||||
password=password,
|
||||
)
|
||||
if password:
|
||||
encryption_algorithm = crypto_serialization.BestAvailableEncryption(
|
||||
password
|
||||
)
|
||||
else:
|
||||
encryption_algorithm = crypto_serialization.NoEncryption()
|
||||
|
||||
file_obj = StringIO(
|
||||
key.private_bytes(
|
||||
crypto_serialization.Encoding.PEM,
|
||||
crypto_serialization.PrivateFormat.OpenSSH,
|
||||
encryption_algorithm,
|
||||
).decode("utf-8")
|
||||
)
|
||||
if isinstance(key, rsa.RSAPrivateKey):
|
||||
private_key = RSAKey.from_private_key(file_obj, password)
|
||||
elif isinstance(key, ed25519.Ed25519PrivateKey):
|
||||
private_key = Ed25519Key.from_private_key(file_obj, password)
|
||||
elif isinstance(key, ec.EllipticCurvePrivateKey):
|
||||
private_key = ECDSAKey.from_private_key(file_obj, password)
|
||||
elif isinstance(key, dsa.DSAPrivateKey):
|
||||
private_key = DSSKey.from_private_key(file_obj, password)
|
||||
else:
|
||||
raise TypeError
|
||||
return private_key
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user