Merge "Implement IPsec Cert-Renewal Operation"
This commit is contained in:
commit
6945a0fd6b
|
@ -46,7 +46,7 @@ def main():
|
|||
help="If enabled, the logging level will be set "
|
||||
"to DEBUG instead of the default INFO level.")
|
||||
parser.add_argument("-o", "--opcode", metavar='<opcode>',
|
||||
type=int, choices=[1, 2, 3],
|
||||
type=int, choices=[1, 2],
|
||||
help='Operational code (Default: ' + str(opcode) + ')')
|
||||
args = parser.parse_args()
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
class Client(object):
|
||||
|
||||
def __init__(self, host, port, opcode):
|
||||
def __init__(self, host, port, op_code):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.opcode = opcode
|
||||
self.op_code = str(op_code)
|
||||
self.state = State.STAGE_1
|
||||
self.ifname = utils.get_management_interface()
|
||||
self.personality = utils.get_personality()
|
||||
|
@ -45,7 +45,7 @@ class Client(object):
|
|||
# Generate message 1 - OP/MAC/HASH
|
||||
def _generate_message_1(self):
|
||||
message = {}
|
||||
message['op'] = str(self.opcode)
|
||||
message['op'] = self.op_code
|
||||
message['mac_addr'] = self.mac_addr
|
||||
message['hash'] = utils.hash_payload(message)
|
||||
|
||||
|
@ -159,12 +159,15 @@ class Client(object):
|
|||
if self.state == State.STAGE_4:
|
||||
LOG.info("Received IPSec Auth CSR Response")
|
||||
cert = base64.b64decode(msg['cert'])
|
||||
network = msg['network']
|
||||
digest = base64.b64decode(msg['hash'])
|
||||
|
||||
ca_cert = utils.load_data(constants.TRUSTED_CA_CERT_PATH)
|
||||
|
||||
data = msg['cert'].encode('utf-8') + network.encode('utf-8')
|
||||
data = msg['cert'].encode('utf-8')
|
||||
if self.op_code == constants.OP_CODE_INITIAL_AUTH:
|
||||
network = msg['network']
|
||||
data = data + network.encode('utf-8')
|
||||
|
||||
if not utils.verify_signed_hash(ca_cert, digest, data):
|
||||
msg = "Hash validation failed"
|
||||
LOG.exception("Hash validation failed")
|
||||
|
@ -176,23 +179,46 @@ class Client(object):
|
|||
cert_path = constants.CERT_SYSTEM_LOCAL_DIR + cert_file
|
||||
utils.save_data(cert_path, cert)
|
||||
|
||||
if self.personality == constants.CONTROLLER:
|
||||
self.local_addr = self.hostname[constants.UNIT_HOSTNAME] + ', ' \
|
||||
+ self.hostname[constants.FLOATING_UNIT_HOSTNAME]
|
||||
else:
|
||||
self.local_addr = utils.get_ip_addr(self.ifname)
|
||||
if self.op_code == constants.OP_CODE_INITIAL_AUTH:
|
||||
if self.personality == constants.CONTROLLER:
|
||||
self.local_addr = self.hostname[constants.UNIT_HOSTNAME] + ', ' \
|
||||
+ self.hostname[constants.FLOATING_UNIT_HOSTNAME]
|
||||
else:
|
||||
self.local_addr = utils.get_ip_addr(self.ifname)
|
||||
|
||||
LOG.info("Generating config files and restart ipsec")
|
||||
strong = config.StrongswanPuppet(self.hostname[constants.UNIT_HOSTNAME],
|
||||
self.local_addr, network)
|
||||
strong.generate_file()
|
||||
puppet_cf = subprocess.run(['puppet', 'apply', '-e', 'include ::platform::strongswan'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
|
||||
LOG.info("Generating config files and restart ipsec")
|
||||
strong = config.StrongswanPuppet(self.hostname[constants.UNIT_HOSTNAME],
|
||||
self.local_addr, network)
|
||||
strong.generate_file()
|
||||
puppet_cf = subprocess.run(['puppet', 'apply', '-e',
|
||||
'include ::platform::strongswan'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
check=False)
|
||||
|
||||
if puppet_cf.stderr:
|
||||
err = "Error: %s" % (puppet_cf.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to create strongswan config files: %s" % err)
|
||||
return False
|
||||
if puppet_cf.returncode != 0:
|
||||
err = "Error: %s" % (puppet_cf.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to create StrongSwan config files: %s" % err)
|
||||
return False
|
||||
|
||||
elif self.op_code == constants.OP_CODE_CERT_RENEWAL:
|
||||
load_creds = subprocess.run(['swanctl', '--load-creds'], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, check=False)
|
||||
|
||||
if load_creds.returncode != 0:
|
||||
err = "Error: %s" % (load_creds.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to load StrongSwan credentials: %s" % err)
|
||||
return False
|
||||
|
||||
rekey = subprocess.run(['swanctl', '--rekey', '--ike', constants.IKE_SA_NAME,
|
||||
'--reauth'], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, check=False)
|
||||
|
||||
if rekey.returncode != 0:
|
||||
err = "Error: %s" % (rekey.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to rekey IKE SA with StrongSwan: %s" % err)
|
||||
return False
|
||||
|
||||
LOG.info('IPsec certificate renewed successfully')
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -90,11 +90,11 @@ class SwanctlConf(object):
|
|||
self.node[key] = value
|
||||
|
||||
def get_conf(self):
|
||||
self.children['node'] = self.node
|
||||
self.children[constants.CHILD_SA_NAME] = self.node
|
||||
self.system_nodes['local'] = self.local
|
||||
self.system_nodes['remote'] = self.remote
|
||||
self.system_nodes['children'] = self.children
|
||||
self.connections['system-nodes'] = self.system_nodes
|
||||
self.connections[constants.IKE_SA_NAME] = self.system_nodes
|
||||
return self.connections
|
||||
|
||||
|
||||
|
|
|
@ -49,10 +49,12 @@ PXECONTROLLER_URL = 'http://pxecontroller:6385'
|
|||
|
||||
OP_CODE_INITIAL_AUTH = "1"
|
||||
OP_CODE_CERT_RENEWAL = "2"
|
||||
|
||||
SUPPORTED_OP_CODES = [OP_CODE_INITIAL_AUTH,
|
||||
OP_CODE_CERT_RENEWAL]
|
||||
|
||||
MGMT_IPSEC_ENABLING = 'enabling'
|
||||
MGMT_IPSEC_ENABLED = 'enabled'
|
||||
MGMT_IPSEC_DISABLED = 'disabled'
|
||||
|
||||
CHILD_SA_NAME = 'node'
|
||||
IKE_SA_NAME = 'system-nodes'
|
||||
|
|
|
@ -282,7 +282,7 @@ def kube_apply_certificate_request(body):
|
|||
elif get_cr.stderr and 'NotFound' not in str(get_cr.stderr):
|
||||
err = "Error: %s" % (get_cr.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to retrieve CertificateRequest resource info. %s" % (err))
|
||||
return
|
||||
return None
|
||||
|
||||
# Create CertificateRequest resource in kubernetes
|
||||
cr_body = yaml.safe_dump(body, default_flow_style=False)
|
||||
|
@ -292,11 +292,11 @@ def kube_apply_certificate_request(body):
|
|||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
check=False)
|
||||
|
||||
if create_cr.stderr:
|
||||
if create_cr.returncode != 0:
|
||||
err = "Error: %s" % (create_cr.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to create CertificateRequest %s/%s. %s"
|
||||
% (constants.NAMESPACE_DEPLOYMENT, name, err))
|
||||
return
|
||||
return None
|
||||
|
||||
# Get Certificate from recently created resource in kubernetes
|
||||
cmd_get_certificate = ['-o', "jsonpath='{.status.certificate}'"]
|
||||
|
@ -305,10 +305,10 @@ def kube_apply_certificate_request(body):
|
|||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
check=False)
|
||||
|
||||
if signed_cert.stderr:
|
||||
if signed_cert.returncode != 0:
|
||||
err = "Error: %s" % (signed_cert.stderr.decode("utf-8"))
|
||||
LOG.exception("Failed to retrieve %s/%s's Certificate. %s"
|
||||
% (constants.NAMESPACE_DEPLOYMENT, name, err))
|
||||
return
|
||||
return None
|
||||
|
||||
return signed_cert.stdout.decode("utf-8").strip("'")
|
||||
|
|
|
@ -90,6 +90,7 @@ class IPsecConnection(object):
|
|||
CA_CRT = 'tls.crt'
|
||||
|
||||
def __init__(self):
|
||||
self.op_code = None
|
||||
self.hostname = None
|
||||
self.mgmt_subnet = None
|
||||
self.signed_cert = None
|
||||
|
@ -153,7 +154,6 @@ class IPsecConnection(object):
|
|||
raise ConnectionRefusedError(msg)
|
||||
|
||||
client_data = utils.get_client_hostname_and_mgmt_subnet(mac_addr)
|
||||
|
||||
self.hostname = client_data['hostname']
|
||||
self.mgmt_subnet = client_data['mgmt_subnet']
|
||||
|
||||
|
@ -199,12 +199,14 @@ class IPsecConnection(object):
|
|||
if not self.signed_cert:
|
||||
raise ValueError('Unable to sign certificate request')
|
||||
|
||||
cert = bytes(self.signed_cert, 'utf-8')
|
||||
network = bytes(self.mgmt_subnet, 'utf-8')
|
||||
hash_payload = utils.hash_and_sign_payload(self.ca_key, cert + network)
|
||||
data = bytes(self.signed_cert, 'utf-8')
|
||||
if self.op_code == constants.OP_CODE_INITIAL_AUTH:
|
||||
payload["network"] = self.mgmt_subnet
|
||||
data = data + bytes(self.mgmt_subnet, 'utf-8')
|
||||
|
||||
hash_payload = utils.hash_and_sign_payload(self.ca_key, data)
|
||||
|
||||
payload["cert"] = self.signed_cert
|
||||
payload["network"] = self.mgmt_subnet
|
||||
payload["hash"] = hash_payload.decode("utf-8")
|
||||
|
||||
LOG.info("Sending IPSec Auth CSR Response")
|
||||
|
|
Loading…
Reference in New Issue