Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9db9afae8d |
@@ -47,9 +47,9 @@ profiles::helpers::certmanager::vault_config:
|
|||||||
|
|
||||||
profiles::helpers::sshsignhost::vault_config:
|
profiles::helpers::sshsignhost::vault_config:
|
||||||
addr: 'https://vault.service.consul:8200'
|
addr: 'https://vault.service.consul:8200'
|
||||||
mount_point: 'ssh-host-signer'
|
mount_point: 'sshca'
|
||||||
approle_path: 'approle'
|
approle_path: 'approle'
|
||||||
role_name: 'hostrole'
|
role_name: 'signhost'
|
||||||
output_path: '/tmp/sshsignhost'
|
output_path: '/tmp/sshsignhost'
|
||||||
role_id: "%{lookup('sshsignhost::role_id')}"
|
role_id: "%{lookup('sshsignhost::role_id')}"
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ class profiles::helpers::certmanager (
|
|||||||
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
||||||
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
||||||
Hash $vault_config = {},
|
Hash $vault_config = {},
|
||||||
|
Enum['approle','kubernetes'] $auth_method = 'approle',
|
||||||
|
String[1] $k8s_mount = 'k8s/au/syd1',
|
||||||
|
String[1] $k8s_role = 'puppet_certmanager',
|
||||||
|
Stdlib::AbsolutePath $jwt_path = '/var/run/secrets/kubernetes.io/serviceaccount/token',
|
||||||
String $owner = 'root',
|
String $owner = 'root',
|
||||||
String $group = 'root',
|
String $group = 'root',
|
||||||
Boolean $systempkgs = false,
|
Boolean $systempkgs = false,
|
||||||
@@ -16,6 +20,14 @@ class profiles::helpers::certmanager (
|
|||||||
|
|
||||||
if $::facts['python3_version'] {
|
if $::facts['python3_version'] {
|
||||||
|
|
||||||
|
# class parameters supply the auth defaults; $vault_config may override them
|
||||||
|
$vault_settings = {
|
||||||
|
'auth_method' => $auth_method,
|
||||||
|
'k8s_mount' => $k8s_mount,
|
||||||
|
'k8s_role' => $k8s_role,
|
||||||
|
'jwt_path' => $jwt_path,
|
||||||
|
} + $vault_config
|
||||||
|
|
||||||
$python_version = $version ? {
|
$python_version = $version ? {
|
||||||
'system' => $::facts['python3_version'],
|
'system' => $::facts['python3_version'],
|
||||||
default => $version,
|
default => $version,
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ class profiles::helpers::sshsignhost (
|
|||||||
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
||||||
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
||||||
Hash $vault_config = {},
|
Hash $vault_config = {},
|
||||||
|
Enum['approle','kubernetes'] $auth_method = 'approle',
|
||||||
|
String[1] $k8s_mount = 'k8s/au/syd1',
|
||||||
|
String[1] $k8s_role = 'puppet_sshsigner',
|
||||||
|
Stdlib::AbsolutePath $jwt_path = '/var/run/secrets/kubernetes.io/serviceaccount/token',
|
||||||
String $owner = 'root',
|
String $owner = 'root',
|
||||||
String $group = 'root',
|
String $group = 'root',
|
||||||
Boolean $systempkgs = false,
|
Boolean $systempkgs = false,
|
||||||
@@ -16,6 +20,14 @@ class profiles::helpers::sshsignhost (
|
|||||||
|
|
||||||
if $::facts['python3_version'] {
|
if $::facts['python3_version'] {
|
||||||
|
|
||||||
|
# class parameters supply the auth defaults; $vault_config may override them
|
||||||
|
$vault_settings = {
|
||||||
|
'auth_method' => $auth_method,
|
||||||
|
'k8s_mount' => $k8s_mount,
|
||||||
|
'k8s_role' => $k8s_role,
|
||||||
|
'jwt_path' => $jwt_path,
|
||||||
|
} + $vault_config
|
||||||
|
|
||||||
$python_version = $version ? {
|
$python_version = $version ? {
|
||||||
'system' => $::facts['python3_version'],
|
'system' => $::facts['python3_version'],
|
||||||
default => $version,
|
default => $version,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!<%= @venv_path %>/bin/python
|
#!<%= @venv_path %>/bin/python
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@@ -25,14 +26,50 @@ def authenticate_approle(vault_config):
|
|||||||
auth_response = response.json()
|
auth_response = response.json()
|
||||||
return auth_response['auth']['client_token']
|
return auth_response['auth']['client_token']
|
||||||
else:
|
else:
|
||||||
print(f"Error authenticating with AppRole: {response.text}")
|
print(f"Error authenticating with AppRole: {response.text}", file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
class VaultAuthError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def authenticate_kubernetes(vault_config):
|
||||||
|
jwt_path = vault_config.get('jwt_path') or '/var/run/secrets/kubernetes.io/serviceaccount/token'
|
||||||
|
try:
|
||||||
|
with open(jwt_path, 'r') as file:
|
||||||
|
jwt = file.read().strip()
|
||||||
|
except OSError as error:
|
||||||
|
raise VaultAuthError(f"cannot read service account token '{jwt_path}': {error}")
|
||||||
|
if not jwt:
|
||||||
|
raise VaultAuthError(f"service account token '{jwt_path}' is empty")
|
||||||
|
url = f"{vault_config['addr']}/v1/auth/{vault_config['k8s_mount']}/login"
|
||||||
|
payload = {
|
||||||
|
"role": vault_config['k8s_role'],
|
||||||
|
"jwt": jwt,
|
||||||
|
}
|
||||||
|
response = requests.post(url, json=payload, verify=False)
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise VaultAuthError(
|
||||||
|
f"kubernetes login as role '{vault_config['k8s_role']}' on mount "
|
||||||
|
f"'{vault_config['k8s_mount']}' was rejected ({response.status_code}): {response.text}"
|
||||||
|
)
|
||||||
|
return response.json()['auth']['client_token']
|
||||||
|
|
||||||
|
def authenticate(vault_config):
|
||||||
|
auth_method = vault_config.get('auth_method', 'approle')
|
||||||
|
if auth_method == 'approle':
|
||||||
|
client_token = authenticate_approle(vault_config)
|
||||||
|
if not client_token:
|
||||||
|
raise VaultAuthError("approle login was rejected")
|
||||||
|
return client_token
|
||||||
|
if auth_method == 'kubernetes':
|
||||||
|
return authenticate_kubernetes(vault_config)
|
||||||
|
raise VaultAuthError(f"unsupported auth_method '{auth_method}': expected 'approle' or 'kubernetes'")
|
||||||
|
|
||||||
def request_certificate(common_name, alt_names, ip_sans, expiry_days, vault_config):
|
def request_certificate(common_name, alt_names, ip_sans, expiry_days, vault_config):
|
||||||
# Authenticate using AppRole and get a token
|
try:
|
||||||
client_token = authenticate_approle(vault_config)
|
client_token = authenticate(vault_config)
|
||||||
if not client_token:
|
except VaultAuthError as error:
|
||||||
print("Failed to authenticate with Vault using AppRole.")
|
print(f"Failed to authenticate with Vault: {error}", file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
url = f"{vault_config['addr']}/v1/{vault_config['mount_point']}/issue/{vault_config['role_name']}"
|
url = f"{vault_config['addr']}/v1/{vault_config['mount_point']}/issue/{vault_config['role_name']}"
|
||||||
@@ -47,7 +84,7 @@ def request_certificate(common_name, alt_names, ip_sans, expiry_days, vault_conf
|
|||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return response.json()
|
return response.json()
|
||||||
else:
|
else:
|
||||||
print(f"Error requesting certificate: {response.text}")
|
print(f"Error requesting certificate: {response.text}", file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def save_cert_files(certificate_response, common_name, compress, config, json_output):
|
def save_cert_files(certificate_response, common_name, compress, config, json_output):
|
||||||
@@ -95,7 +132,8 @@ def main(config_file):
|
|||||||
else:
|
else:
|
||||||
save_cert_files(certificate_response, args.common_name, args.compress, config, False)
|
save_cert_files(certificate_response, args.common_name, args.compress, config, False)
|
||||||
else:
|
else:
|
||||||
print("Failed to obtain certificate.")
|
print("Failed to obtain certificate.", file=sys.stderr)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config_file = '<%= @config_path %>'
|
config_file = '<%= @config_path %>'
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
vault:
|
vault:
|
||||||
addr: '<%= @vault_config['addr'] %>'
|
addr: '<%= @vault_settings['addr'] %>'
|
||||||
role_id: '<%= @vault_config['role_id'] %>'
|
auth_method: '<%= @vault_settings['auth_method'] %>'
|
||||||
approle_path: '<%= @vault_config['approle_path'] %>'
|
<% if @vault_settings['auth_method'] == 'kubernetes' -%>
|
||||||
mount_point: '<%= @vault_config['mount_point'] %>'
|
k8s_mount: '<%= @vault_settings['k8s_mount'] %>'
|
||||||
role_name: '<%= @vault_config['role_name'] %>'
|
k8s_role: '<%= @vault_settings['k8s_role'] %>'
|
||||||
output_path: '<%= @vault_config['output_path'] %>'
|
jwt_path: '<%= @vault_settings['jwt_path'] %>'
|
||||||
|
<% else -%>
|
||||||
|
role_id: '<%= @vault_settings['role_id'] %>'
|
||||||
|
approle_path: '<%= @vault_settings['approle_path'] %>'
|
||||||
|
<% end -%>
|
||||||
|
mount_point: '<%= @vault_settings['mount_point'] %>'
|
||||||
|
role_name: '<%= @vault_settings['role_name'] %>'
|
||||||
|
output_path: '<%= @vault_settings['output_path'] %>'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!<%= @venv_path %>/bin/python
|
#!<%= @venv_path %>/bin/python
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
import yaml
|
import yaml
|
||||||
@@ -22,14 +23,50 @@ def authenticate_approle(vault_config):
|
|||||||
auth_response = response.json()
|
auth_response = response.json()
|
||||||
return auth_response['auth']['client_token']
|
return auth_response['auth']['client_token']
|
||||||
else:
|
else:
|
||||||
print(f"Error authenticating with AppRole: {response.text}")
|
print(f"Error authenticating with AppRole: {response.text}", file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
class VaultAuthError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def authenticate_kubernetes(vault_config):
|
||||||
|
jwt_path = vault_config.get('jwt_path') or '/var/run/secrets/kubernetes.io/serviceaccount/token'
|
||||||
|
try:
|
||||||
|
with open(jwt_path, 'r') as file:
|
||||||
|
jwt = file.read().strip()
|
||||||
|
except OSError as error:
|
||||||
|
raise VaultAuthError(f"cannot read service account token '{jwt_path}': {error}")
|
||||||
|
if not jwt:
|
||||||
|
raise VaultAuthError(f"service account token '{jwt_path}' is empty")
|
||||||
|
url = f"{vault_config['addr']}/v1/auth/{vault_config['k8s_mount']}/login"
|
||||||
|
payload = {
|
||||||
|
"role": vault_config['k8s_role'],
|
||||||
|
"jwt": jwt,
|
||||||
|
}
|
||||||
|
response = requests.post(url, json=payload, verify=False)
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise VaultAuthError(
|
||||||
|
f"kubernetes login as role '{vault_config['k8s_role']}' on mount "
|
||||||
|
f"'{vault_config['k8s_mount']}' was rejected ({response.status_code}): {response.text}"
|
||||||
|
)
|
||||||
|
return response.json()['auth']['client_token']
|
||||||
|
|
||||||
|
def authenticate(vault_config):
|
||||||
|
auth_method = vault_config.get('auth_method', 'approle')
|
||||||
|
if auth_method == 'approle':
|
||||||
|
client_token = authenticate_approle(vault_config)
|
||||||
|
if not client_token:
|
||||||
|
raise VaultAuthError("approle login was rejected")
|
||||||
|
return client_token
|
||||||
|
if auth_method == 'kubernetes':
|
||||||
|
return authenticate_kubernetes(vault_config)
|
||||||
|
raise VaultAuthError(f"unsupported auth_method '{auth_method}': expected 'approle' or 'kubernetes'")
|
||||||
|
|
||||||
def sign_ssh_certificate(vault_config, public_key, valid_principals, ttl):
|
def sign_ssh_certificate(vault_config, public_key, valid_principals, ttl):
|
||||||
# Authenticate using AppRole and get a token
|
try:
|
||||||
client_token = authenticate_approle(vault_config)
|
client_token = authenticate(vault_config)
|
||||||
if not client_token:
|
except VaultAuthError as error:
|
||||||
print("Failed to authenticate with Vault using AppRole.")
|
print(f"Failed to authenticate with Vault: {error}", file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Prepare the SSH certificate signing request
|
# Prepare the SSH certificate signing request
|
||||||
@@ -47,7 +84,7 @@ def sign_ssh_certificate(vault_config, public_key, valid_principals, ttl):
|
|||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return response.json()
|
return response.json()
|
||||||
else:
|
else:
|
||||||
print(f"Error requesting certificate: {response.text}")
|
print(f"Error requesting certificate: {response.text}", file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def main(config_file):
|
def main(config_file):
|
||||||
@@ -75,7 +112,7 @@ def main(config_file):
|
|||||||
else:
|
else:
|
||||||
print(response['data']['signed_key'])
|
print(response['data']['signed_key'])
|
||||||
else:
|
else:
|
||||||
print("Error: The response does not contain the expected data.")
|
print("Error: The response does not contain the expected data.", file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
vault:
|
vault:
|
||||||
addr: '<%= @vault_config['addr'] %>'
|
addr: '<%= @vault_settings['addr'] %>'
|
||||||
role_id: '<%= @vault_config['role_id'] %>'
|
auth_method: '<%= @vault_settings['auth_method'] %>'
|
||||||
approle_path: '<%= @vault_config['approle_path'] %>'
|
<% if @vault_settings['auth_method'] == 'kubernetes' -%>
|
||||||
mount_point: '<%= @vault_config['mount_point'] %>'
|
k8s_mount: '<%= @vault_settings['k8s_mount'] %>'
|
||||||
role_name: '<%= @vault_config['role_name'] %>'
|
k8s_role: '<%= @vault_settings['k8s_role'] %>'
|
||||||
output_path: '<%= @vault_config['output_path'] %>'
|
jwt_path: '<%= @vault_settings['jwt_path'] %>'
|
||||||
|
<% else -%>
|
||||||
|
role_id: '<%= @vault_settings['role_id'] %>'
|
||||||
|
approle_path: '<%= @vault_settings['approle_path'] %>'
|
||||||
|
<% end -%>
|
||||||
|
mount_point: '<%= @vault_settings['mount_point'] %>'
|
||||||
|
role_name: '<%= @vault_settings['role_name'] %>'
|
||||||
|
output_path: '<%= @vault_settings['output_path'] %>'
|
||||||
|
|||||||
Reference in New Issue
Block a user