gvasalt/states/_states/rsa_key.py

122 lines
3.7 KiB
Python

# -*- coding: utf-8 -*-
#
# some internal functions are copied from salt.states.file
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import os
def _check_user(user, group):
"""
Checks if the named user and group are present on the minion
"""
err = ""
if user:
uid = __salt__["file.user_to_uid"](user)
if uid == "":
err += "User {0} is not available ".format(user)
if group:
gid = __salt__["file.group_to_gid"](group)
if gid == "":
err += "Group {0} is not available".format(group)
return err
def _error(ret, err_msg):
ret["result"] = False
ret["comment"] = err_msg
return ret
def _calculate_umask(mode):
mode = str(mode).lstrip("0")
if not mode:
mode = "0"
modeint = int(mode, 8)
return modeint ^ 0o777
def valid_key(name, bits=2048, user=None, group=None, mode="0700"):
"""
Make sure that the given key file exists and contains a valid RSA key.
name
The name of the key file to check
bits
Minimum bits for the RSA key
user
The user to own the file, this defaults to the user salt is running as
on the minion
group
The group ownership set for the file, this defaults to the group salt
is running on the minion
mode
The permissions set on the file, this defaults to 0600
"""
mode = __salt__["config.manage_mode"](mode)
ret = {"name": name, "changes": {}, "result": None, "comment": ""}
if not os.path.isfile(name) and __opts__["test"]:
ret["comment"] = "would create RSA key in file {0}".format(name)
return ret
u_check = _check_user(user, group)
if u_check:
return _error(ret, u_check)
if not os.path.isabs(name):
return _error(ret, "Specified file {0} is not an absolute path".format(name))
if os.path.isdir(name):
return _error(ret, "Specified target {0} is a directory".format(name))
if os.path.exists(name):
ret, perms = __salt__["file.check_perms"](name, ret, user, group, mode)
if __opts__["test"]:
ret["comment"] = "File {0} not updated".format(name)
return ret
if not os.path.isfile(name):
rsakey = rsa.generate_private_key(
public_exponent=65537, key_size=bits, backend=default_backend()
)
oldumask = os.umask(_calculate_umask(mode))
with open(name, "wb") as rsafile:
rsafile.write(
rsakey.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
)
os.umask(oldumask)
ret["comment"] = "created new RSA key and saved PEM file {0}".format(name)
ret["changes"]["created"] = name
ret["result"] = True
return ret
try:
with open(name, "rb") as rsafile:
rsakey = serialization.load_pem_private_key(
rsafile.read(), password=None, backend=default_backend()
)
except Exception as e:
ret["comment"] = "error loading RSA key from file {0}: {1}".format(name, e)
ret["result"] = False
return ret
if rsakey.key_size < bits:
ret["comment"] = (
"RSA key in {0} is only {1} bits, which is less than the "
"required {2} bits".format(name, rsakey.key_size, bits)
)
ret["result"] = False
else:
ret["comment"] = "RSA key in file {0} is ok ({1} bits)".format(
name, rsakey.key_size
)
ret["result"] = True
return ret