golden hour
/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules
⬆️ Go Up
Upload
File/Folder
Size
Actions
__init__.py
35 B
Del
OK
__pycache__
-
Del
OK
acme.py
12.74 KB
Del
OK
aix_group.py
4.12 KB
Del
OK
aix_shadow.py
1.93 KB
Del
OK
aixpkg.py
24.15 KB
Del
OK
aliases.py
5.07 KB
Del
OK
alternatives.py
5.71 KB
Del
OK
ansiblegate.py
19.51 KB
Del
OK
apache.py
12.47 KB
Del
OK
apcups.py
2.15 KB
Del
OK
apf.py
3.09 KB
Del
OK
apkpkg.py
16 KB
Del
OK
aptly.py
15.28 KB
Del
OK
aptpkg.py
116.64 KB
Del
OK
archive.py
48.63 KB
Del
OK
arista_pyeapi.py
22.06 KB
Del
OK
artifactory.py
24.78 KB
Del
OK
at.py
10.72 KB
Del
OK
at_solaris.py
8.51 KB
Del
OK
augeas_cfg.py
13.93 KB
Del
OK
aws_sqs.py
6.55 KB
Del
OK
azurearm_compute.py
20.8 KB
Del
OK
azurearm_dns.py
15.8 KB
Del
OK
azurearm_network.py
82.99 KB
Del
OK
azurearm_resource.py
35.75 KB
Del
OK
bamboohr.py
7.36 KB
Del
OK
baredoc.py
11.13 KB
Del
OK
bcache.py
28.97 KB
Del
OK
beacons.py
27.82 KB
Del
OK
bigip.py
69.11 KB
Del
OK
bluez_bluetooth.py
6.76 KB
Del
OK
boto3_elasticache.py
37.34 KB
Del
OK
boto3_elasticsearch.py
53.17 KB
Del
OK
boto3_route53.py
39.82 KB
Del
OK
boto3_sns.py
12.93 KB
Del
OK
boto_apigateway.py
61.86 KB
Del
OK
boto_asg.py
35.69 KB
Del
OK
boto_cfn.py
7.95 KB
Del
OK
boto_cloudfront.py
12.75 KB
Del
OK
boto_cloudtrail.py
14.45 KB
Del
OK
boto_cloudwatch.py
10.99 KB
Del
OK
boto_cloudwatch_event.py
9.48 KB
Del
OK
boto_cognitoidentity.py
14.63 KB
Del
OK
boto_datapipeline.py
6.94 KB
Del
OK
boto_dynamodb.py
14.98 KB
Del
OK
boto_ec2.py
79.27 KB
Del
OK
boto_efs.py
14.05 KB
Del
OK
boto_elasticache.py
23.69 KB
Del
OK
boto_elasticsearch_domain.py
15.85 KB
Del
OK
boto_elb.py
35.53 KB
Del
OK
boto_elbv2.py
10.78 KB
Del
OK
boto_iam.py
75.62 KB
Del
OK
boto_iot.py
26.2 KB
Del
OK
boto_kinesis.py
19.62 KB
Del
OK
boto_kms.py
17.29 KB
Del
OK
boto_lambda.py
35.05 KB
Del
OK
boto_rds.py
34.92 KB
Del
OK
boto_route53.py
32.55 KB
Del
OK
boto_s3.py
4.24 KB
Del
OK
boto_s3_bucket.py
31.8 KB
Del
OK
boto_secgroup.py
25.22 KB
Del
OK
boto_sns.py
7.22 KB
Del
OK
boto_sqs.py
6.43 KB
Del
OK
boto_ssm.py
3.63 KB
Del
OK
boto_vpc.py
113.08 KB
Del
OK
bower.py
5.85 KB
Del
OK
bridge.py
10.81 KB
Del
OK
bsd_shadow.py
6.25 KB
Del
OK
btrfs.py
33.66 KB
Del
OK
cabal.py
3.79 KB
Del
OK
capirca_acl.py
40.04 KB
Del
OK
cassandra_cql.py
54.16 KB
Del
OK
cassandra_mod.py
4.3 KB
Del
OK
celery.py
3.33 KB
Del
OK
ceph.py
15.82 KB
Del
OK
chassis.py
1.52 KB
Del
OK
chef.py
4.66 KB
Del
OK
chocolatey.py
41.55 KB
Del
OK
chronos.py
2.89 KB
Del
OK
chroot.py
11.73 KB
Del
OK
cimc.py
23.02 KB
Del
OK
ciscoconfparse_mod.py
14.79 KB
Del
OK
cisconso.py
3.83 KB
Del
OK
cloud.py
9.39 KB
Del
OK
cmdmod.py
163.73 KB
Del
OK
composer.py
10.31 KB
Del
OK
config.py
16.98 KB
Del
OK
consul.py
69.3 KB
Del
OK
container_resource.py
12.94 KB
Del
OK
cp.py
31.98 KB
Del
OK
cpan.py
5.54 KB
Del
OK
cron.py
28.09 KB
Del
OK
cryptdev.py
10.08 KB
Del
OK
csf.py
16.04 KB
Del
OK
cyg.py
8.32 KB
Del
OK
daemontools.py
5.41 KB
Del
OK
data.py
3.85 KB
Del
OK
datadog_api.py
7.76 KB
Del
OK
ddns.py
7.12 KB
Del
OK
deb_apache.py
7.41 KB
Del
OK
deb_postgres.py
4.18 KB
Del
OK
debconfmod.py
4.06 KB
Del
OK
debian_ip.py
64.91 KB
Del
OK
debian_service.py
6.55 KB
Del
OK
debuild_pkgbuild.py
34.68 KB
Del
OK
defaults.py
6.55 KB
Del
OK
devinfo.py
9.07 KB
Del
OK
devmap.py
627 B
Del
OK
dig.py
8.75 KB
Del
OK
disk.py
30.82 KB
Del
OK
djangomod.py
7.53 KB
Del
OK
dnsmasq.py
5.71 KB
Del
OK
dnsutil.py
11.51 KB
Del
OK
dockercompose.py
32.62 KB
Del
OK
dockermod.py
224.85 KB
Del
OK
dpkg_lowpkg.py
12.94 KB
Del
OK
drac.py
10.97 KB
Del
OK
dracr.py
38.53 KB
Del
OK
drbd.py
7.19 KB
Del
OK
dummyproxy_pkg.py
2.46 KB
Del
OK
dummyproxy_service.py
2.91 KB
Del
OK
ebuildpkg.py
38.74 KB
Del
OK
eix.py
1.58 KB
Del
OK
elasticsearch.py
51.44 KB
Del
OK
environ.py
8.96 KB
Del
OK
eselect.py
4.99 KB
Del
OK
esxcluster.py
1.66 KB
Del
OK
esxdatacenter.py
1.68 KB
Del
OK
esxi.py
2.79 KB
Del
OK
esxvm.py
1.63 KB
Del
OK
etcd_mod.py
8.56 KB
Del
OK
ethtool.py
11.12 KB
Del
OK
event.py
7.67 KB
Del
OK
extfs.py
8.78 KB
Del
OK
file.py
232.18 KB
Del
OK
firewalld.py
20.51 KB
Del
OK
freebsd_sysctl.py
4.99 KB
Del
OK
freebsd_update.py
6.19 KB
Del
OK
freebsdjail.py
7.16 KB
Del
OK
freebsdkmod.py
6.17 KB
Del
OK
freebsdpkg.py
17.04 KB
Del
OK
freebsdports.py
13.13 KB
Del
OK
freebsdservice.py
12.53 KB
Del
OK
freezer.py
10.2 KB
Del
OK
gcp_addon.py
4.07 KB
Del
OK
gem.py
10.6 KB
Del
OK
genesis.py
21.75 KB
Del
OK
gentoo_service.py
9.18 KB
Del
OK
gentoolkitmod.py
8.39 KB
Del
OK
git.py
172.01 KB
Del
OK
github.py
53.19 KB
Del
OK
glanceng.py
4.69 KB
Del
OK
glassfish.py
19.49 KB
Del
OK
glusterfs.py
19.55 KB
Del
OK
gnomedesktop.py
6.85 KB
Del
OK
google_chat.py
1.52 KB
Del
OK
gpg.py
39.09 KB
Del
OK
grafana4.py
30.27 KB
Del
OK
grains.py
21.81 KB
Del
OK
groupadd.py
11.87 KB
Del
OK
grub_legacy.py
3.08 KB
Del
OK
guestfs.py
2.37 KB
Del
OK
hadoop.py
3.76 KB
Del
OK
haproxyconn.py
10.17 KB
Del
OK
hashutil.py
6.77 KB
Del
OK
heat.py
25.25 KB
Del
OK
helm.py
39.27 KB
Del
OK
hg.py
7.16 KB
Del
OK
highstate_doc.py
22.76 KB
Del
OK
hosts.py
10.47 KB
Del
OK
http.py
3.76 KB
Del
OK
icinga2.py
4.46 KB
Del
OK
idem.py
1.75 KB
Del
OK
ifttt.py
2.28 KB
Del
OK
ilo.py
15.98 KB
Del
OK
incron.py
7.68 KB
Del
OK
influxdb08mod.py
15.07 KB
Del
OK
influxdbmod.py
16.13 KB
Del
OK
infoblox.py
17.53 KB
Del
OK
ini_manage.py
14.63 KB
Del
OK
inspectlib
-
Del
OK
inspector.py
8.19 KB
Del
OK
introspect.py
4.02 KB
Del
OK
iosconfig.py
14.78 KB
Del
OK
ipmi.py
25.47 KB
Del
OK
ipset.py
17.97 KB
Del
OK
iptables.py
57.44 KB
Del
OK
iwtools.py
3.99 KB
Del
OK
jboss7.py
20.51 KB
Del
OK
jboss7_cli.py
15.23 KB
Del
OK
jenkinsmod.py
11.9 KB
Del
OK
jinja.py
2.66 KB
Del
OK
jira_mod.py
7.07 KB
Del
OK
junos.py
73.96 KB
Del
OK
k8s.py
24.87 KB
Del
OK
kapacitor.py
5.37 KB
Del
OK
kerberos.py
5.42 KB
Del
OK
kernelpkg_linux_apt.py
6.71 KB
Del
OK
kernelpkg_linux_yum.py
7.26 KB
Del
OK
key.py
1007 B
Del
OK
keyboard.py
2.64 KB
Del
OK
keystone.py
43.14 KB
Del
OK
keystoneng.py
21.82 KB
Del
OK
keystore.py
7.18 KB
Del
OK
kmod.py
7.65 KB
Del
OK
kubeadm.py
34.64 KB
Del
OK
kubernetesmod.py
46.77 KB
Del
OK
launchctl_service.py
9.69 KB
Del
OK
layman.py
4.22 KB
Del
OK
ldap3.py
18.81 KB
Del
OK
ldapmod.py
5.9 KB
Del
OK
libcloud_compute.py
23.48 KB
Del
OK
libcloud_dns.py
9.73 KB
Del
OK
libcloud_loadbalancer.py
13.14 KB
Del
OK
libcloud_storage.py
12.16 KB
Del
OK
linux_acl.py
7.7 KB
Del
OK
linux_ip.py
5.55 KB
Del
OK
linux_lvm.py
17.86 KB
Del
OK
linux_service.py
4.64 KB
Del
OK
linux_shadow.py
12.96 KB
Del
OK
linux_sysctl.py
7.5 KB
Del
OK
localemod.py
11.84 KB
Del
OK
locate.py
2.58 KB
Del
OK
logadm.py
9.44 KB
Del
OK
logmod.py
1.25 KB
Del
OK
logrotate.py
7.72 KB
Del
OK
lvs.py
11.54 KB
Del
OK
lxc.py
147.27 KB
Del
OK
lxd.py
90.07 KB
Del
OK
mac_assistive.py
11.37 KB
Del
OK
mac_brew_pkg.py
19.91 KB
Del
OK
mac_desktop.py
2.77 KB
Del
OK
mac_group.py
6.62 KB
Del
OK
mac_keychain.py
6.39 KB
Del
OK
mac_pkgutil.py
2.84 KB
Del
OK
mac_portspkg.py
11.36 KB
Del
OK
mac_power.py
13.29 KB
Del
OK
mac_service.py
19.64 KB
Del
OK
mac_shadow.py
14.23 KB
Del
OK
mac_softwareupdate.py
14.52 KB
Del
OK
mac_sysctl.py
5.13 KB
Del
OK
mac_system.py
15.07 KB
Del
OK
mac_timezone.py
8.34 KB
Del
OK
mac_user.py
16.41 KB
Del
OK
mac_xattr.py
6.27 KB
Del
OK
macdefaults.py
2.33 KB
Del
OK
macpackage.py
6.66 KB
Del
OK
makeconf.py
17.31 KB
Del
OK
mandrill.py
6.31 KB
Del
OK
marathon.py
5.36 KB
Del
OK
match.py
13 KB
Del
OK
mattermost.py
3.4 KB
Del
OK
mdadm_raid.py
9.86 KB
Del
OK
mdata.py
3.38 KB
Del
OK
memcached.py
6.13 KB
Del
OK
mine.py
18.84 KB
Del
OK
minion.py
7.68 KB
Del
OK
mod_random.py
7.18 KB
Del
OK
modjk.py
12.48 KB
Del
OK
mongodb.py
29.75 KB
Del
OK
monit.py
5.51 KB
Del
OK
moosefs.py
3.87 KB
Del
OK
mount.py
58.44 KB
Del
OK
mssql.py
14.64 KB
Del
OK
msteams.py
2.11 KB
Del
OK
munin.py
2.4 KB
Del
OK
mysql.py
90.66 KB
Del
OK
nacl.py
9.72 KB
Del
OK
nagios.py
6.53 KB
Del
OK
nagios_rpc.py
5.09 KB
Del
OK
namecheap_domains.py
12.84 KB
Del
OK
namecheap_domains_dns.py
5.93 KB
Del
OK
namecheap_domains_ns.py
4.51 KB
Del
OK
namecheap_ssl.py
25.69 KB
Del
OK
namecheap_users.py
2.4 KB
Del
OK
napalm_bgp.py
9.72 KB
Del
OK
napalm_formula.py
11.33 KB
Del
OK
napalm_mod.py
61.37 KB
Del
OK
napalm_netacl.py
28.59 KB
Del
OK
napalm_network.py
93.22 KB
Del
OK
napalm_ntp.py
10.22 KB
Del
OK
napalm_probes.py
13.25 KB
Del
OK
napalm_route.py
5.09 KB
Del
OK
napalm_snmp.py
7.05 KB
Del
OK
napalm_users.py
6.49 KB
Del
OK
napalm_yang_mod.py
20.28 KB
Del
OK
netaddress.py
1.6 KB
Del
OK
netbox.py
32.22 KB
Del
OK
netbsd_sysctl.py
3.92 KB
Del
OK
netbsdservice.py
6.43 KB
Del
OK
netmiko_mod.py
19.61 KB
Del
OK
netscaler.py
27.02 KB
Del
OK
network.py
63.42 KB
Del
OK
neutron.py
44.92 KB
Del
OK
neutronng.py
15.02 KB
Del
OK
nexus.py
22.95 KB
Del
OK
nfs3.py
3.9 KB
Del
OK
nftables.py
33.58 KB
Del
OK
nginx.py
3.83 KB
Del
OK
nilrt_ip.py
36.18 KB
Del
OK
nix.py
8.03 KB
Del
OK
nova.py
19.6 KB
Del
OK
npm.py
10.4 KB
Del
OK
nspawn.py
41.35 KB
Del
OK
nxos.py
24.65 KB
Del
OK
nxos_api.py
14.72 KB
Del
OK
nxos_upgrade.py
14.74 KB
Del
OK
omapi.py
3.6 KB
Del
OK
openbsd_sysctl.py
3.74 KB
Del
OK
openbsdpkg.py
10.97 KB
Del
OK
openbsdrcctl_service.py
6.33 KB
Del
OK
openbsdservice.py
8.31 KB
Del
OK
openscap.py
2.81 KB
Del
OK
openstack_config.py
3.21 KB
Del
OK
openstack_mng.py
2.71 KB
Del
OK
openvswitch.py
17.19 KB
Del
OK
opkg.py
49.67 KB
Del
OK
opsgenie.py
3.29 KB
Del
OK
oracle.py
5.82 KB
Del
OK
osquery.py
24.93 KB
Del
OK
out.py
2.53 KB
Del
OK
pacmanpkg.py
31.92 KB
Del
OK
pagerduty.py
4.7 KB
Del
OK
pagerduty_util.py
13.48 KB
Del
OK
pam.py
2.01 KB
Del
OK
panos.py
61.05 KB
Del
OK
parallels.py
19.85 KB
Del
OK
parted_partition.py
21.53 KB
Del
OK
pcs.py
14.11 KB
Del
OK
pdbedit.py
10.79 KB
Del
OK
pecl.py
3.79 KB
Del
OK
peeringdb.py
8.39 KB
Del
OK
pf.py
9.51 KB
Del
OK
philips_hue.py
1.55 KB
Del
OK
pillar.py
21.37 KB
Del
OK
pip.py
53.42 KB
Del
OK
pkg_resource.py
12.3 KB
Del
OK
pkgin.py
17.29 KB
Del
OK
pkgng.py
61.07 KB
Del
OK
pkgutil.py
9.85 KB
Del
OK
portage_config.py
22.73 KB
Del
OK
postfix.py
16.24 KB
Del
OK
postgres.py
88.24 KB
Del
OK
poudriere.py
7.85 KB
Del
OK
powerpath.py
2.57 KB
Del
OK
proxy.py
11.49 KB
Del
OK
ps.py
20.89 KB
Del
OK
publish.py
10.25 KB
Del
OK
puppet.py
10.9 KB
Del
OK
purefa.py
33.59 KB
Del
OK
purefb.py
13.69 KB
Del
OK
pushbullet.py
1.88 KB
Del
OK
pushover_notify.py
3.48 KB
Del
OK
pw_group.py
4.62 KB
Del
OK
pw_user.py
12.47 KB
Del
OK
pyenv.py
6.93 KB
Del
OK
qemu_img.py
1.53 KB
Del
OK
qemu_nbd.py
3.28 KB
Del
OK
quota.py
6.43 KB
Del
OK
rabbitmq.py
38.4 KB
Del
OK
rallydev.py
6.09 KB
Del
OK
random_org.py
23.76 KB
Del
OK
rbac_solaris.py
16.05 KB
Del
OK
rbenv.py
10.75 KB
Del
OK
rdp.py
6.08 KB
Del
OK
rebootmgr.py
7.68 KB
Del
OK
redismod.py
16.36 KB
Del
OK
reg.py
16.36 KB
Del
OK
rest_pkg.py
2.26 KB
Del
OK
rest_sample_utils.py
558 B
Del
OK
rest_service.py
3.63 KB
Del
OK
restartcheck.py
24.1 KB
Del
OK
restconf.py
3.15 KB
Del
OK
ret.py
1.27 KB
Del
OK
rh_ip.py
38.55 KB
Del
OK
rh_service.py
16.61 KB
Del
OK
riak.py
5.19 KB
Del
OK
rpm_lowpkg.py
27.67 KB
Del
OK
rpmbuild_pkgbuild.py
24.53 KB
Del
OK
rsync.py
8.04 KB
Del
OK
runit.py
17.17 KB
Del
OK
rvm.py
11.1 KB
Del
OK
s3.py
9.93 KB
Del
OK
s6.py
3.62 KB
Del
OK
salt_proxy.py
4.48 KB
Del
OK
salt_version.py
4.58 KB
Del
OK
saltcheck.py
46.66 KB
Del
OK
saltcloudmod.py
954 B
Del
OK
saltutil.py
57.49 KB
Del
OK
schedule.py
50.81 KB
Del
OK
scp_mod.py
6.22 KB
Del
OK
scsi.py
2.66 KB
Del
OK
sdb.py
2.48 KB
Del
OK
seed.py
8.87 KB
Del
OK
selinux.py
24.2 KB
Del
OK
sensehat.py
7.79 KB
Del
OK
sensors.py
1.3 KB
Del
OK
serverdensity_device.py
8.1 KB
Del
OK
servicenow.py
4.36 KB
Del
OK
slack_notify.py
7.83 KB
Del
OK
slackware_service.py
6.84 KB
Del
OK
slsutil.py
19.04 KB
Del
OK
smartos_imgadm.py
12.04 KB
Del
OK
smartos_nictagadm.py
6.46 KB
Del
OK
smartos_virt.py
5.21 KB
Del
OK
smartos_vmadm.py
26.2 KB
Del
OK
smbios.py
10.05 KB
Del
OK
smf_service.py
8.52 KB
Del
OK
smtp.py
5.41 KB
Del
OK
snapper.py
27.14 KB
Del
OK
solaris_fmadm.py
11.2 KB
Del
OK
solaris_group.py
2.8 KB
Del
OK
solaris_shadow.py
7.98 KB
Del
OK
solaris_system.py
3.72 KB
Del
OK
solaris_user.py
11.06 KB
Del
OK
solarisipspkg.py
18.68 KB
Del
OK
solarispkg.py
15.4 KB
Del
OK
solr.py
45.54 KB
Del
OK
solrcloud.py
14.63 KB
Del
OK
splunk.py
8.14 KB
Del
OK
splunk_search.py
8.76 KB
Del
OK
sqlite3.py
2.54 KB
Del
OK
ssh.py
43.89 KB
Del
OK
ssh_pkg.py
1.08 KB
Del
OK
ssh_service.py
3.39 KB
Del
OK
state.py
82.34 KB
Del
OK
status.py
57.79 KB
Del
OK
statuspage.py
14.67 KB
Del
OK
supervisord.py
11.15 KB
Del
OK
suse_apache.py
2.45 KB
Del
OK
suse_ip.py
35.72 KB
Del
OK
svn.py
10.75 KB
Del
OK
swarm.py
13.5 KB
Del
OK
swift.py
5.53 KB
Del
OK
sysbench.py
6.62 KB
Del
OK
sysfs.py
6.61 KB
Del
OK
syslog_ng.py
31.52 KB
Del
OK
sysmod.py
22.59 KB
Del
OK
sysrc.py
3.38 KB
Del
OK
system.py
19.28 KB
Del
OK
system_profiler.py
3.54 KB
Del
OK
systemd_service.py
46.29 KB
Del
OK
telegram.py
3.28 KB
Del
OK
telemetry.py
12.87 KB
Del
OK
temp.py
831 B
Del
OK
test.py
15.4 KB
Del
OK
test_virtual.py
237 B
Del
OK
testinframod.py
9.92 KB
Del
OK
textfsm_mod.py
16.22 KB
Del
OK
timezone.py
19.98 KB
Del
OK
tls.py
58.63 KB
Del
OK
tomcat.py
18.59 KB
Del
OK
trafficserver.py
10.44 KB
Del
OK
transactional_update.py
35.83 KB
Del
OK
travisci.py
2.05 KB
Del
OK
tuned.py
2.34 KB
Del
OK
twilio_notify.py
2.95 KB
Del
OK
udev.py
3.72 KB
Del
OK
upstart_service.py
16.92 KB
Del
OK
uptime.py
3.23 KB
Del
OK
useradd.py
22.63 KB
Del
OK
uwsgi.py
996 B
Del
OK
vagrant.py
20.4 KB
Del
OK
varnish.py
3.08 KB
Del
OK
vault.py
15.61 KB
Del
OK
vbox_guest.py
10.55 KB
Del
OK
vboxmanage.py
14.71 KB
Del
OK
vcenter.py
1.61 KB
Del
OK
victorops.py
6.54 KB
Del
OK
virt.py
287.71 KB
Del
OK
virtualenv_mod.py
15.09 KB
Del
OK
vmctl.py
9.56 KB
Del
OK
vsphere.py
380.41 KB
Del
OK
webutil.py
3.66 KB
Del
OK
win_auditpol.py
4.74 KB
Del
OK
win_autoruns.py
2.29 KB
Del
OK
win_certutil.py
4.55 KB
Del
OK
win_dacl.py
32.27 KB
Del
OK
win_disk.py
1.8 KB
Del
OK
win_dism.py
20.7 KB
Del
OK
win_dns_client.py
4.19 KB
Del
OK
win_dsc.py
27.54 KB
Del
OK
win_event.py
22.32 KB
Del
OK
win_file.py
64.39 KB
Del
OK
win_firewall.py
20.15 KB
Del
OK
win_groupadd.py
11.27 KB
Del
OK
win_iis.py
68.78 KB
Del
OK
win_ip.py
11.43 KB
Del
OK
win_lgpo.py
491.76 KB
Del
OK
win_lgpo_reg.py
17.9 KB
Del
OK
win_license.py
2.72 KB
Del
OK
win_network.py
13.9 KB
Del
OK
win_ntp.py
1.8 KB
Del
OK
win_path.py
11.12 KB
Del
OK
win_pkg.py
86.43 KB
Del
OK
win_pki.py
15.8 KB
Del
OK
win_powercfg.py
9.85 KB
Del
OK
win_psget.py
8.97 KB
Del
OK
win_servermanager.py
14.21 KB
Del
OK
win_service.py
32.96 KB
Del
OK
win_shadow.py
3.03 KB
Del
OK
win_shortcut.py
16.49 KB
Del
OK
win_smtp_server.py
17.67 KB
Del
OK
win_snmp.py
13.38 KB
Del
OK
win_status.py
16.94 KB
Del
OK
win_system.py
40.61 KB
Del
OK
win_task.py
79.17 KB
Del
OK
win_timezone.py
13.3 KB
Del
OK
win_useradd.py
27.39 KB
Del
OK
win_wua.py
38.29 KB
Del
OK
win_wusa.py
5.88 KB
Del
OK
winrepo.py
6.09 KB
Del
OK
wordpress.py
4.71 KB
Del
OK
x509.py
63.1 KB
Del
OK
x509_v2.py
74.15 KB
Del
OK
xapi_virt.py
24.07 KB
Del
OK
xbpspkg.py
15.84 KB
Del
OK
xfs.py
15.35 KB
Del
OK
xml.py
2.14 KB
Del
OK
xmpp.py
5.28 KB
Del
OK
yaml.py
1.94 KB
Del
OK
yumpkg.py
116.5 KB
Del
OK
zabbix.py
97.55 KB
Del
OK
zcbuildout.py
28.16 KB
Del
OK
zenoss.py
5.64 KB
Del
OK
zfs.py
34.44 KB
Del
OK
zk_concurrency.py
11.16 KB
Del
OK
znc.py
2.26 KB
Del
OK
zoneadm.py
15.05 KB
Del
OK
zonecfg.py
21.85 KB
Del
OK
zookeeper.py
14.72 KB
Del
OK
zpool.py
44.02 KB
Del
OK
zypperpkg.py
94.87 KB
Del
OK
Edit: tls.py
r""" A salt module for SSL/TLS. Can create a Certificate Authority (CA) or use Self-Signed certificates. :depends: PyOpenSSL Python module (0.10 or later, 0.14 or later for X509 extension support) :configuration: Add the following values in /etc/salt/minion for the CA module to function properly: .. code-block:: yaml ca.cert_base_path: '/etc/pki' CLI Example #1: Creating a CA, a server request and its signed certificate: .. code-block:: bash # salt-call tls.create_ca my_little \ days=5 \ CN='My Little CA' \ C=US \ ST=Utah \ L=Salt Lake City \ O=Saltstack \ emailAddress=pleasedontemail@example.com Created Private Key: "/etc/pki/my_little/my_little_ca_cert.key" Created CA "my_little_ca": "/etc/pki/my_little_ca/my_little_ca_cert.crt" # salt-call tls.create_csr my_little CN=www.example.com Created Private Key: "/etc/pki/my_little/certs/www.example.com.key Created CSR for "www.example.com": "/etc/pki/my_little/certs/www.example.com.csr" # salt-call tls.create_ca_signed_cert my_little CN=www.example.com Created Certificate for "www.example.com": /etc/pki/my_little/certs/www.example.com.crt" CLI Example #2: Creating a client request and its signed certificate .. code-block:: bash # salt-call tls.create_csr my_little CN=DBReplica_No.1 cert_type=client Created Private Key: "/etc/pki/my_little/certs//DBReplica_No.1.key" Created CSR for "DBReplica_No.1": "/etc/pki/my_little/certs/DBReplica_No.1.csr" # salt-call tls.create_ca_signed_cert my_little CN=DBReplica_No.1 Created Certificate for "DBReplica_No.1": "/etc/pki/my_little/certs/DBReplica_No.1.crt" CLI Example #3: Creating both a server and client req + cert for the same CN .. code-block:: bash # salt-call tls.create_csr my_little CN=MasterDBReplica_No.2 \ cert_type=client Created Private Key: "/etc/pki/my_little/certs/MasterDBReplica_No.2.key" Created CSR for "DBReplica_No.1": "/etc/pki/my_little/certs/MasterDBReplica_No.2.csr" # salt-call tls.create_ca_signed_cert my_little CN=MasterDBReplica_No.2 Created Certificate for "DBReplica_No.1": "/etc/pki/my_little/certs/DBReplica_No.1.crt" # salt-call tls.create_csr my_little CN=MasterDBReplica_No.2 \ cert_type=server Certificate "MasterDBReplica_No.2" already exists (doh!) # salt-call tls.create_csr my_little CN=MasterDBReplica_No.2 \ cert_type=server type_ext=True Created Private Key: "/etc/pki/my_little/certs/DBReplica_No.1_client.key" Created CSR for "DBReplica_No.1": "/etc/pki/my_little/certs/DBReplica_No.1_client.csr" # salt-call tls.create_ca_signed_cert my_little CN=MasterDBReplica_No.2 Certificate "MasterDBReplica_No.2" already exists (DOH!) # salt-call tls.create_ca_signed_cert my_little CN=MasterDBReplica_No.2 \ cert_type=server type_ext=True Created Certificate for "MasterDBReplica_No.2": "/etc/pki/my_little/certs/MasterDBReplica_No.2_server.crt" CLI Example #4: Create a server req + cert with non-CN filename for the cert .. code-block:: bash # salt-call tls.create_csr my_little CN=www.anothersometh.ing \ cert_type=server type_ext=True Created Private Key: "/etc/pki/my_little/certs/www.anothersometh.ing_server.key" Created CSR for "DBReplica_No.1": "/etc/pki/my_little/certs/www.anothersometh.ing_server.csr" # salt-call tls_create_ca_signed_cert my_little CN=www.anothersometh.ing \ cert_type=server cert_filename="something_completely_different" Created Certificate for "www.anothersometh.ing": /etc/pki/my_little/certs/something_completely_different.crt """ import binascii import calendar import logging import math import os import re import time from datetime import datetime import salt.utils.data import salt.utils.files import salt.utils.stringutils from salt.exceptions import CommandExecutionError from salt.utils.versions import Version # pylint: disable=C0103 HAS_SSL = False X509_EXT_ENABLED = True try: import OpenSSL HAS_SSL = True OpenSSL_version = Version(OpenSSL.__dict__.get("__version__", "0.0")) except ImportError: pass log = logging.getLogger(__name__) two_digit_year_fmt = "%y%m%d%H%M%SZ" four_digit_year_fmt = "%Y%m%d%H%M%SZ" def __virtual__(): """ Only load this module if the ca config options are set """ global X509_EXT_ENABLED if HAS_SSL and OpenSSL_version >= Version("0.10"): if OpenSSL_version < Version("0.14"): X509_EXT_ENABLED = False log.debug( "You should upgrade pyOpenSSL to at least 0.14.1 to " "enable the use of X509 extensions in the tls module" ) elif OpenSSL_version <= Version("0.15"): log.debug( "You should upgrade pyOpenSSL to at least 0.15.1 to " "enable the full use of X509 extensions in the tls module" ) # NOTE: Not having configured a cert path should not prevent this # module from loading as it provides methods to configure the path. return True else: X509_EXT_ENABLED = False return ( False, "PyOpenSSL version 0.10 or later must be installed " "before this module can be used.", ) def _microtime(): """ Return a Unix timestamp as a string of digits :return: """ val1, val2 = math.modf(time.time()) val2 = int(val2) return "{:f}{}".format(val1, val2) def _context_or_config(key): """ Return the value corresponding to the key in __context__ or if not present, fallback to config.option. """ return __context__.get(key, __salt__["config.option"](key)) def cert_base_path(cacert_path=None): """ Return the base path for certs from CLI or from options cacert_path absolute path to ca certificates root directory CLI Example: .. code-block:: bash salt '*' tls.cert_base_path """ return ( cacert_path or _context_or_config("ca.contextual_cert_base_path") or _context_or_config("ca.cert_base_path") ) def _cert_base_path(cacert_path=None): """ Retrocompatible wrapper """ return cert_base_path(cacert_path) def set_ca_path(cacert_path): """ If wanted, store the aforementioned cacert_path in context to be used as the basepath for further operations CLI Example: .. code-block:: bash salt '*' tls.set_ca_path /etc/certs """ if cacert_path: __context__["ca.contextual_cert_base_path"] = cacert_path return cert_base_path() def _new_serial(ca_name): """ Return a serial number in hex using os.urandom() and a Unix timestamp in microseconds. ca_name name of the CA CN common name in the request """ hashnum = int( binascii.hexlify( b"_".join( ( salt.utils.stringutils.to_bytes(_microtime()), os.urandom(5), ) ) ), 16, ) log.debug("Hashnum: %s", hashnum) # record the hash somewhere cachedir = __opts__["cachedir"] log.debug("cachedir: %s", cachedir) serial_file = "{}/{}.serial".format(cachedir, ca_name) if not os.path.exists(cachedir): os.makedirs(cachedir) if not os.path.exists(serial_file): mode = "w" else: mode = "a+" with salt.utils.files.fopen(serial_file, mode) as ofile: ofile.write(str(hashnum)) return hashnum def _four_digit_year_to_two_digit(datetimeObj): return datetimeObj.strftime(two_digit_year_fmt) def _get_basic_info(ca_name, cert, ca_dir=None): """ Get basic info to write out to the index.txt """ if ca_dir is None: ca_dir = "{}/{}".format(_cert_base_path(), ca_name) index_file = "{}/index.txt".format(ca_dir) cert = _read_cert(cert) expire_date = _four_digit_year_to_two_digit(_get_expiration_date(cert)) serial_number = format(cert.get_serial_number(), "X") # gotta prepend a / subject = "/" # then we can add the rest of the subject subject += "/".join( ["{}={}".format(x, y) for x, y in cert.get_subject().get_components()] ) subject += "\n" return (index_file, expire_date, serial_number, subject) def _write_cert_to_database(ca_name, cert, cacert_path=None, status="V"): """ write out the index.txt database file in the appropriate directory to track certificates ca_name name of the CA cert certificate to be recorded """ set_ca_path(cacert_path) ca_dir = "{}/{}".format(cert_base_path(), ca_name) index_file, expire_date, serial_number, subject = _get_basic_info( ca_name, cert, ca_dir ) index_data = "{}\t{}\t\t{}\tunknown\t{}".format( status, expire_date, serial_number, subject ) with salt.utils.files.fopen(index_file, "a+") as ofile: ofile.write(salt.utils.stringutils.to_str(index_data)) def maybe_fix_ssl_version(ca_name, cacert_path=None, ca_filename=None): """ Check that the X509 version is correct (was incorrectly set in previous salt versions). This will fix the version if needed. ca_name ca authority name cacert_path absolute path to ca certificates root directory ca_filename alternative filename for the CA .. versionadded:: 2015.5.3 CLI Example: .. code-block:: bash salt '*' tls.maybe_fix_ssl_version test_ca /etc/certs """ set_ca_path(cacert_path) if not ca_filename: ca_filename = "{}_ca_cert".format(ca_name) certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) ca_keyp = "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) with salt.utils.files.fopen(certp) as fic: cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, fic.read()) if cert.get_version() == 3: log.info("Regenerating wrong x509 version for certificate %s", certp) with salt.utils.files.fopen(ca_keyp) as fic2: try: # try to determine the key bits key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fic2.read() ) bits = key.bits() except Exception: # pylint: disable=broad-except bits = 2048 try: days = ( datetime.strptime(cert.get_notAfter(), "%Y%m%d%H%M%SZ") - datetime.utcnow() ).days except (ValueError, TypeError): days = 365 subj = cert.get_subject() create_ca( ca_name, bits=bits, days=days, CN=subj.CN, C=subj.C, ST=subj.ST, L=subj.L, O=subj.O, OU=subj.OU, emailAddress=subj.emailAddress, fixmode=True, ) def ca_exists(ca_name, cacert_path=None, ca_filename=None): """ Verify whether a Certificate Authority (CA) already exists ca_name name of the CA cacert_path absolute path to ca certificates root directory ca_filename alternative filename for the CA .. versionadded:: 2015.5.3 CLI Example: .. code-block:: bash salt '*' tls.ca_exists test_ca /etc/certs """ set_ca_path(cacert_path) if not ca_filename: ca_filename = "{}_ca_cert".format(ca_name) certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) if os.path.exists(certp): maybe_fix_ssl_version(ca_name, cacert_path=cacert_path, ca_filename=ca_filename) return True return False def _ca_exists(ca_name, cacert_path=None): """Retrocompatible wrapper""" return ca_exists(ca_name, cacert_path) def get_ca(ca_name, as_text=False, cacert_path=None): """ Get the certificate path or content ca_name name of the CA as_text if true, return the certificate content instead of the path cacert_path absolute path to ca certificates root directory CLI Example: .. code-block:: bash salt '*' tls.get_ca test_ca as_text=False cacert_path=/etc/certs """ set_ca_path(cacert_path) certp = "{0}/{1}/{1}_ca_cert.crt".format(cert_base_path(), ca_name) if not os.path.exists(certp): raise ValueError("Certificate does not exist for {}".format(ca_name)) else: if as_text: with salt.utils.files.fopen(certp) as fic: certp = salt.utils.stringutils.to_unicode(fic.read()) return certp def get_ca_signed_cert( ca_name, CN="localhost", as_text=False, cacert_path=None, cert_filename=None ): """ Get the certificate path or content ca_name name of the CA CN common name of the certificate as_text if true, return the certificate content instead of the path cacert_path absolute path to certificates root directory cert_filename alternative filename for the certificate, useful when using special characters in the CN .. versionadded:: 2015.5.3 CLI Example: .. code-block:: bash salt '*' tls.get_ca_signed_cert test_ca CN=localhost as_text=False cacert_path=/etc/certs """ set_ca_path(cacert_path) if not cert_filename: cert_filename = CN certp = "{}/{}/certs/{}.crt".format(cert_base_path(), ca_name, cert_filename) if not os.path.exists(certp): raise ValueError("Certificate does not exists for {}".format(CN)) else: if as_text: with salt.utils.files.fopen(certp) as fic: certp = salt.utils.stringutils.to_unicode(fic.read()) return certp def get_ca_signed_key( ca_name, CN="localhost", as_text=False, cacert_path=None, key_filename=None ): """ Get the certificate path or content ca_name name of the CA CN common name of the certificate as_text if true, return the certificate content instead of the path cacert_path absolute path to certificates root directory key_filename alternative filename for the key, useful when using special characters .. versionadded:: 2015.5.3 in the CN CLI Example: .. code-block:: bash salt '*' tls.get_ca_signed_key \ test_ca CN=localhost \ as_text=False \ cacert_path=/etc/certs """ set_ca_path(cacert_path) if not key_filename: key_filename = CN keyp = "{}/{}/certs/{}.key".format(cert_base_path(), ca_name, key_filename) if not os.path.exists(keyp): raise ValueError("Certificate does not exists for {}".format(CN)) else: if as_text: with salt.utils.files.fopen(keyp) as fic: keyp = salt.utils.stringutils.to_unicode(fic.read()) return keyp def _read_cert(cert): if isinstance(cert, str): try: with salt.utils.files.fopen(cert) as rfh: return OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, rfh.read() ) except Exception: # pylint: disable=broad-except log.exception("Failed to read cert from path %s", cert) return None else: if not hasattr(cert, "get_notAfter"): log.error("%s is not a valid cert path/object", cert) return None else: return cert def validate(cert, ca_name, crl_file): """ .. versionadded:: 3000 Validate a certificate against a given CA/CRL. cert path to the certifiate PEM file or string ca_name name of the CA crl_file full path to the CRL file """ store = OpenSSL.crypto.X509Store() cert_obj = _read_cert(cert) if cert_obj is None: raise CommandExecutionError( "Failed to read cert from {}, see log for details".format(cert) ) ca_dir = "{}/{}".format(cert_base_path(), ca_name) ca_cert = _read_cert("{}/{}_ca_cert.crt".format(ca_dir, ca_name)) store.add_cert(ca_cert) # These flags tell OpenSSL to check the leaf as well as the # entire cert chain. X509StoreFlags = OpenSSL.crypto.X509StoreFlags store.set_flags(X509StoreFlags.CRL_CHECK | X509StoreFlags.CRL_CHECK_ALL) if crl_file is None: crl = OpenSSL.crypto.CRL() else: with salt.utils.files.fopen(crl_file) as fhr: crl = OpenSSL.crypto.load_crl(OpenSSL.crypto.FILETYPE_PEM, fhr.read()) store.add_crl(crl) context = OpenSSL.crypto.X509StoreContext(store, cert_obj) ret = {} try: context.verify_certificate() ret["valid"] = True except OpenSSL.crypto.X509StoreContextError as e: ret["error"] = str(e) ret["error_cert"] = e.certificate ret["valid"] = False return ret def _get_expiration_date(cert): """ Returns a datetime.datetime object """ cert_obj = _read_cert(cert) if cert_obj is None: raise CommandExecutionError( "Failed to read cert from {}, see log for details".format(cert) ) return datetime.strptime( salt.utils.stringutils.to_str(cert_obj.get_notAfter()), four_digit_year_fmt ) def get_expiration_date(cert, date_format="%Y-%m-%d"): """ .. versionadded:: 2019.2.0 Get a certificate's expiration date cert Full path to the certificate date_format By default this will return the expiration date in YYYY-MM-DD format, use this to specify a different strftime format string. Note that the expiration time will be in UTC. CLI Examples: .. code-block:: bash salt '*' tls.get_expiration_date /path/to/foo.crt salt '*' tls.get_expiration_date /path/to/foo.crt date_format='%d/%m/%Y' """ return _get_expiration_date(cert).strftime(date_format) def _check_onlyif_unless(onlyif, unless): ret = None retcode = __salt__["cmd.retcode"] if onlyif is not None: if not isinstance(onlyif, str): if not onlyif: ret = {"comment": "onlyif condition is false", "result": True} elif isinstance(onlyif, str): if retcode(onlyif) != 0: ret = {"comment": "onlyif condition is false", "result": True} log.debug("onlyif condition is false") if unless is not None: if not isinstance(unless, str): if unless: ret = {"comment": "unless condition is true", "result": True} elif isinstance(unless, str): if retcode(unless) == 0: ret = {"comment": "unless condition is true", "result": True} log.debug("unless condition is true") return ret def create_ca( ca_name, bits=2048, days=365, CN="localhost", C="US", ST="Utah", L="Salt Lake City", O="SaltStack", OU=None, emailAddress=None, fixmode=False, cacert_path=None, ca_filename=None, digest="sha256", onlyif=None, unless=None, replace=False, ): """ Create a Certificate Authority (CA) ca_name name of the CA bits number of RSA key bits, default is 2048 days number of days the CA will be valid, default is 365 CN common name in the request, default is "localhost" C country, default is "US" ST state, default is "Utah" L locality, default is "Centerville", the city where SaltStack originated O organization, default is "SaltStack" OU organizational unit, default is None emailAddress email address for the CA owner, default is None cacert_path absolute path to ca certificates root directory ca_filename alternative filename for the CA .. versionadded:: 2015.5.3 digest The message digest algorithm. Must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1". Default: 'sha256' replace Replace this certificate even if it exists .. versionadded:: 2015.5.1 Writes out a CA certificate based upon defined config values. If the file already exists, the function just returns assuming the CA certificate already exists. If the following values were set:: ca.cert_base_path='/etc/pki' ca_name='koji' the resulting CA, and corresponding key, would be written in the following location with appropriate permissions:: /etc/pki/koji/koji_ca_cert.crt /etc/pki/koji/koji_ca_cert.key CLI Example: .. code-block:: bash salt '*' tls.create_ca test_ca """ status = _check_onlyif_unless(onlyif, unless) if status is not None: return None set_ca_path(cacert_path) if not ca_filename: ca_filename = "{}_ca_cert".format(ca_name) certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) ca_keyp = "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) if not replace and not fixmode and ca_exists(ca_name, ca_filename=ca_filename): return 'Certificate for CA named "{}" already exists'.format(ca_name) if fixmode and not os.path.exists(certp): raise ValueError("{} does not exists, can't fix".format(certp)) if not os.path.exists("{}/{}".format(cert_base_path(), ca_name)): os.makedirs("{}/{}".format(cert_base_path(), ca_name)) # try to reuse existing ssl key key = None if os.path.exists(ca_keyp): with salt.utils.files.fopen(ca_keyp) as fic2: # try to determine the key bits try: key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fic2.read() ) except OpenSSL.crypto.Error as err: log.warning( "Error loading existing private key %s, generating a new key: %s", ca_keyp, err, ) bck = "{}.unloadable.{}".format( ca_keyp, datetime.utcnow().strftime("%Y%m%d%H%M%S") ) log.info("Saving unloadable CA ssl key in %s", bck) os.rename(ca_keyp, bck) if not key: key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) ca = OpenSSL.crypto.X509() ca.set_version(2) ca.set_serial_number(_new_serial(ca_name)) ca.get_subject().C = C ca.get_subject().ST = ST ca.get_subject().L = L ca.get_subject().O = O if OU: ca.get_subject().OU = OU ca.get_subject().CN = CN if emailAddress: ca.get_subject().emailAddress = emailAddress ca.gmtime_adj_notBefore(0) ca.gmtime_adj_notAfter(int(days) * 24 * 60 * 60) ca.set_issuer(ca.get_subject()) ca.set_pubkey(key) if X509_EXT_ENABLED: ca.add_extensions( [ OpenSSL.crypto.X509Extension( b"basicConstraints", True, b"CA:TRUE, pathlen:0" ), OpenSSL.crypto.X509Extension( b"keyUsage", True, b"keyCertSign, cRLSign" ), OpenSSL.crypto.X509Extension( b"subjectKeyIdentifier", False, b"hash", subject=ca ), ] ) ca.add_extensions( [ OpenSSL.crypto.X509Extension( b"authorityKeyIdentifier", False, b"issuer:always,keyid:always", issuer=ca, ) ] ) ca.sign(key, salt.utils.stringutils.to_str(digest)) # always backup existing keys in case keycontent = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key) write_key = True if os.path.exists(ca_keyp): bck = "{}.{}".format(ca_keyp, datetime.utcnow().strftime("%Y%m%d%H%M%S")) with salt.utils.files.fopen(ca_keyp) as fic: old_key = salt.utils.stringutils.to_unicode(fic.read()).strip() if old_key.strip() == keycontent.strip(): write_key = False else: log.info("Saving old CA ssl key in %s", bck) fp = os.open(bck, os.O_CREAT | os.O_RDWR, 0o600) with salt.utils.files.fopen(fp, "w") as bckf: bckf.write(old_key) if write_key: fp = os.open(ca_keyp, os.O_CREAT | os.O_RDWR, 0o600) with salt.utils.files.fopen(fp, "wb") as ca_key: ca_key.write(salt.utils.stringutils.to_bytes(keycontent)) with salt.utils.files.fopen(certp, "wb") as ca_crt: ca_crt.write( salt.utils.stringutils.to_bytes( OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca) ) ) _write_cert_to_database(ca_name, ca) ret = 'Created Private Key: "{}/{}/{}.key" '.format( cert_base_path(), ca_name, ca_filename ) ret += 'Created CA "{0}": "{1}/{0}/{2}.crt"'.format( ca_name, cert_base_path(), ca_filename ) return ret def get_extensions(cert_type): """ Fetch X509 and CSR extension definitions from tls:extensions: (common|server|client) or set them to standard defaults. .. versionadded:: 2015.8.0 cert_type: The type of certificate such as ``server`` or ``client``. CLI Example: .. code-block:: bash salt '*' tls.get_extensions client """ assert X509_EXT_ENABLED, ( "X509 extensions are not supported in " "pyOpenSSL prior to version 0.15.1. Your " "version: {}".format(OpenSSL_version) ) ext = {} if cert_type == "": log.error( "cert_type set to empty in tls_ca.get_extensions(); " "defaulting to ``server``" ) cert_type = "server" try: ext["common"] = __salt__["pillar.get"]("tls.extensions:common", False) except NameError as err: log.debug(err) if not ext["common"] or ext["common"] == "": ext["common"] = { "csr": {"basicConstraints": "CA:FALSE"}, "cert": { "authorityKeyIdentifier": "keyid,issuer:always", "subjectKeyIdentifier": "hash", }, } try: ext["server"] = __salt__["pillar.get"]("tls.extensions:server", False) except NameError as err: log.debug(err) if not ext["server"] or ext["server"] == "": ext["server"] = { "csr": { "extendedKeyUsage": "serverAuth", "keyUsage": "digitalSignature, keyEncipherment", }, "cert": {}, } try: ext["client"] = __salt__["pillar.get"]("tls.extensions:client", False) except NameError as err: log.debug(err) if not ext["client"] or ext["client"] == "": ext["client"] = { "csr": { "extendedKeyUsage": "clientAuth", "keyUsage": "nonRepudiation, digitalSignature, keyEncipherment", }, "cert": {}, } # possible user-defined profile or a typo if cert_type not in ext: try: ext[cert_type] = __salt__["pillar.get"]( "tls.extensions:{}".format(cert_type) ) except NameError as e: log.debug( "pillar, tls:extensions:%s not available or " "not operating in a salt context\n%s", cert_type, e, ) retval = ext["common"] for Use in retval: retval[Use].update(ext[cert_type][Use]) return retval def create_csr( ca_name, bits=2048, CN="localhost", C="US", ST="Utah", L="Salt Lake City", O="SaltStack", OU=None, emailAddress=None, subjectAltName=None, cacert_path=None, ca_filename=None, csr_path=None, csr_filename=None, digest="sha256", type_ext=False, cert_type="server", replace=False, ): """ Create a Certificate Signing Request (CSR) for a particular Certificate Authority (CA) ca_name name of the CA bits number of RSA key bits, default is 2048 CN common name in the request, default is "localhost" C country, default is "US" ST state, default is "Utah" L locality, default is "Centerville", the city where SaltStack originated O organization, default is "SaltStack" NOTE: Must the same as CA certificate or an error will be raised OU organizational unit, default is None emailAddress email address for the request, default is None subjectAltName valid subjectAltNames in full form, e.g. to add DNS entry you would call this function with this value: examples: ['DNS:somednsname.com', 'DNS:1.2.3.4', 'IP:1.2.3.4', 'IP:2001:4801:7821:77:be76:4eff:fe11:e51', 'email:me@i.like.pie.com'] .. note:: some libraries do not properly query IP: prefixes, instead looking for the given req. source with a DNS: prefix. To be thorough, you may want to include both DNS: and IP: entries if you are using subjectAltNames for destinations for your TLS connections. e.g.: requests to https://1.2.3.4 will fail from python's requests library w/out the second entry in the above list .. versionadded:: 2015.8.0 cert_type Specify the general certificate type. Can be either `server` or `client`. Indicates the set of common extensions added to the CSR. .. code-block:: cfg server: { 'basicConstraints': 'CA:FALSE', 'extendedKeyUsage': 'serverAuth', 'keyUsage': 'digitalSignature, keyEncipherment' } client: { 'basicConstraints': 'CA:FALSE', 'extendedKeyUsage': 'clientAuth', 'keyUsage': 'nonRepudiation, digitalSignature, keyEncipherment' } type_ext boolean. Whether or not to extend the filename with CN_[cert_type] This can be useful if a server and client certificate are needed for the same CN. Defaults to False to avoid introducing an unexpected file naming pattern The files normally named some_subject_CN.csr and some_subject_CN.key will then be saved replace Replace this signing request even if it exists .. versionadded:: 2015.5.1 Writes out a Certificate Signing Request (CSR) If the file already exists, the function just returns assuming the CSR already exists. If the following values were set:: ca.cert_base_path='/etc/pki' ca_name='koji' CN='test.egavas.org' the resulting CSR, and corresponding key, would be written in the following location with appropriate permissions:: /etc/pki/koji/certs/test.egavas.org.csr /etc/pki/koji/certs/test.egavas.org.key CLI Example: .. code-block:: bash salt '*' tls.create_csr test """ set_ca_path(cacert_path) if not ca_filename: ca_filename = "{}_ca_cert".format(ca_name) if not ca_exists(ca_name, ca_filename=ca_filename): return 'Certificate for CA named "{}" does not exist, please create it first.'.format( ca_name ) if not csr_path: csr_path = "{}/{}/certs/".format(cert_base_path(), ca_name) if not os.path.exists(csr_path): os.makedirs(csr_path) CN_ext = "_{}".format(cert_type) if type_ext else "" if not csr_filename: csr_filename = "{}{}".format(CN, CN_ext) csr_f = "{}/{}.csr".format(csr_path, csr_filename) if not replace and os.path.exists(csr_f): return 'Certificate Request "{}" already exists'.format(csr_f) key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) req = OpenSSL.crypto.X509Req() req.get_subject().C = C req.get_subject().ST = ST req.get_subject().L = L req.get_subject().O = O if OU: req.get_subject().OU = OU req.get_subject().CN = CN if emailAddress: req.get_subject().emailAddress = emailAddress try: extensions = get_extensions(cert_type)["csr"] extension_adds = [] for ext, value in extensions.items(): if isinstance(value, str): value = salt.utils.stringutils.to_bytes(value) extension_adds.append( OpenSSL.crypto.X509Extension( salt.utils.stringutils.to_bytes(ext), False, value ) ) except AssertionError as err: log.error(err) extensions = [] if subjectAltName: if X509_EXT_ENABLED: if isinstance(subjectAltName, str): subjectAltName = [subjectAltName] extension_adds.append( OpenSSL.crypto.X509Extension( b"subjectAltName", False, b", ".join(salt.utils.data.encode(subjectAltName)), ) ) else: raise ValueError( "subjectAltName cannot be set as X509 " "extensions are not supported in pyOpenSSL " "prior to version 0.15.1. Your " "version: {}.".format(OpenSSL_version) ) if X509_EXT_ENABLED: req.add_extensions(extension_adds) req.set_pubkey(key) req.sign(key, salt.utils.stringutils.to_str(digest)) # Write private key and request priv_keyp = "{}/{}.key".format(csr_path, csr_filename) fp = os.open(priv_keyp, os.O_CREAT | os.O_RDWR, 0o600) with salt.utils.files.fopen(fp, "wb+") as priv_key: priv_key.write( salt.utils.stringutils.to_bytes( OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key) ) ) with salt.utils.files.fopen(csr_f, "wb+") as csr: csr.write( salt.utils.stringutils.to_bytes( OpenSSL.crypto.dump_certificate_request( OpenSSL.crypto.FILETYPE_PEM, req ) ) ) ret = 'Created Private Key: "{}{}.key" '.format(csr_path, csr_filename) ret += 'Created CSR for "{}": "{}{}.csr"'.format(CN, csr_path, csr_filename) return ret def create_self_signed_cert( tls_dir="tls", bits=2048, days=365, CN="localhost", C="US", ST="Utah", L="Salt Lake City", O="SaltStack", OU=None, emailAddress=None, cacert_path=None, cert_filename=None, digest="sha256", replace=False, ): """ Create a Self-Signed Certificate (CERT) tls_dir location appended to the ca.cert_base_path, default is 'tls' bits number of RSA key bits, default is 2048 CN common name in the request, default is "localhost" C country, default is "US" ST state, default is "Utah" L locality, default is "Centerville", the city where SaltStack originated O organization, default is "SaltStack" NOTE: Must the same as CA certificate or an error will be raised OU organizational unit, default is None emailAddress email address for the request, default is None cacert_path absolute path to ca certificates root directory digest The message digest algorithm. Must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1". Default: 'sha256' replace Replace this certificate even if it exists .. versionadded:: 2015.5.1 Writes out a Self-Signed Certificate (CERT). If the file already exists, the function just returns. If the following values were set:: ca.cert_base_path='/etc/pki' tls_dir='koji' CN='test.egavas.org' the resulting CERT, and corresponding key, would be written in the following location with appropriate permissions:: /etc/pki/koji/certs/test.egavas.org.crt /etc/pki/koji/certs/test.egavas.org.key CLI Example: .. code-block:: bash salt '*' tls.create_self_signed_cert Passing options from the command line: .. code-block:: bash salt 'minion' tls.create_self_signed_cert CN='test.mysite.org' """ set_ca_path(cacert_path) if not os.path.exists("{}/{}/certs/".format(cert_base_path(), tls_dir)): os.makedirs("{}/{}/certs/".format(cert_base_path(), tls_dir)) if not cert_filename: cert_filename = CN if not replace and os.path.exists( "{}/{}/certs/{}.crt".format(cert_base_path(), tls_dir, cert_filename) ): return 'Certificate "{}" already exists'.format(cert_filename) key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) # create certificate cert = OpenSSL.crypto.X509() cert.set_version(2) cert.gmtime_adj_notBefore(0) cert.gmtime_adj_notAfter(int(days) * 24 * 60 * 60) cert.get_subject().C = C cert.get_subject().ST = ST cert.get_subject().L = L cert.get_subject().O = O if OU: cert.get_subject().OU = OU cert.get_subject().CN = CN if emailAddress: cert.get_subject().emailAddress = emailAddress cert.set_serial_number(_new_serial(tls_dir)) cert.set_issuer(cert.get_subject()) cert.set_pubkey(key) cert.sign(key, salt.utils.stringutils.to_str(digest)) # Write private key and cert priv_key_path = "{}/{}/certs/{}.key".format( cert_base_path(), tls_dir, cert_filename ) fp = os.open(priv_key_path, os.O_CREAT | os.O_RDWR, 0o600) with salt.utils.files.fopen(fp, "wb+") as priv_key: priv_key.write( salt.utils.stringutils.to_bytes( OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key) ) ) crt_path = "{}/{}/certs/{}.crt".format(cert_base_path(), tls_dir, cert_filename) with salt.utils.files.fopen(crt_path, "wb+") as crt: crt.write( salt.utils.stringutils.to_bytes( OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) ) ) _write_cert_to_database(tls_dir, cert) ret = 'Created Private Key: "{}/{}/certs/{}.key" '.format( cert_base_path(), tls_dir, cert_filename ) ret += 'Created Certificate: "{}/{}/certs/{}.crt"'.format( cert_base_path(), tls_dir, cert_filename ) return ret def create_ca_signed_cert( ca_name, CN, days=365, cacert_path=None, ca_filename=None, cert_path=None, cert_filename=None, digest="sha256", cert_type=None, type_ext=False, replace=False, ): """ Create a Certificate (CERT) signed by a named Certificate Authority (CA) If the certificate file already exists, the function just returns assuming the CERT already exists. The CN *must* match an existing CSR generated by create_csr. If it does not, this method does nothing. ca_name name of the CA CN common name matching the certificate signing request days number of days certificate is valid, default is 365 (1 year) cacert_path absolute path to ca certificates root directory ca_filename alternative filename for the CA .. versionadded:: 2015.5.3 cert_path full path to the certificates directory cert_filename alternative filename for the certificate, useful when using special characters in the CN. If this option is set it will override the certificate filename output effects of ``cert_type``. ``type_ext`` will be completely overridden. .. versionadded:: 2015.5.3 digest The message digest algorithm. Must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1". Default: 'sha256' replace Replace this certificate even if it exists .. versionadded:: 2015.5.1 cert_type string. Either 'server' or 'client' (see create_csr() for details). If create_csr(type_ext=True) this function **must** be called with the same cert_type so it can find the CSR file. .. note:: create_csr() defaults to cert_type='server'; therefore, if it was also called with type_ext, cert_type becomes a required argument for create_ca_signed_cert() type_ext bool. If set True, use ``cert_type`` as an extension to the CN when formatting the filename. e.g.: some_subject_CN_server.crt or some_subject_CN_client.crt This facilitates the context where both types are required for the same subject If ``cert_filename`` is `not None`, setting ``type_ext`` has no effect If the following values were set: .. code-block:: text ca.cert_base_path='/etc/pki' ca_name='koji' CN='test.egavas.org' the resulting signed certificate would be written in the following location: .. code-block:: text /etc/pki/koji/certs/test.egavas.org.crt CLI Example: .. code-block:: bash salt '*' tls.create_ca_signed_cert test localhost """ ret = {} set_ca_path(cacert_path) if not ca_filename: ca_filename = "{}_ca_cert".format(ca_name) if not cert_path: cert_path = "{}/{}/certs".format(cert_base_path(), ca_name) if type_ext: if not cert_type: log.error( "type_ext = True but cert_type is unset. Certificate not written." ) return ret elif cert_type: CN_ext = "_{}".format(cert_type) else: CN_ext = "" csr_filename = "{}{}".format(CN, CN_ext) if not cert_filename: cert_filename = "{}{}".format(CN, CN_ext) if not replace and os.path.exists( os.path.join( os.path.sep.join( "{}/{}/certs/{}.crt".format( cert_base_path(), ca_name, cert_filename ).split("/") ) ) ): return 'Certificate "{}" already exists'.format(cert_filename) try: maybe_fix_ssl_version(ca_name, cacert_path=cacert_path, ca_filename=ca_filename) with salt.utils.files.fopen( "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) ) as fhr: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) with salt.utils.files.fopen( "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) ) as fhr: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: ret["retcode"] = 1 ret["comment"] = 'There is no CA named "{}"'.format(ca_name) return ret try: csr_path = "{}/{}.csr".format(cert_path, csr_filename) with salt.utils.files.fopen(csr_path) as fhr: req = OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: ret["retcode"] = 1 ret["comment"] = 'There is no CSR that matches the CN "{}"'.format( cert_filename ) return ret exts = [] try: exts.extend(req.get_extensions()) except AttributeError: try: # see: http://bazaar.launchpad.net/~exarkun/pyopenssl/master/revision/189 # support is there from quite a long time, but without API # so we mimic the newly get_extensions method present in ultra # recent pyopenssl distros log.info( "req.get_extensions() not supported in pyOpenSSL versions " "prior to 0.15. Processing extensions internally. " "Your version: %s", OpenSSL_version, ) native_exts_obj = OpenSSL._util.lib.X509_REQ_get_extensions(req._req) for i in range(OpenSSL._util.lib.sk_X509_EXTENSION_num(native_exts_obj)): ext = OpenSSL.crypto.X509Extension.__new__(OpenSSL.crypto.X509Extension) ext._extension = OpenSSL._util.lib.sk_X509_EXTENSION_value( native_exts_obj, i ) exts.append(ext) except Exception: # pylint: disable=broad-except log.error( "X509 extensions are unsupported in pyOpenSSL " "versions prior to 0.14. Upgrade required to " "use extensions. Current version: %s", OpenSSL_version, ) cert = OpenSSL.crypto.X509() cert.set_version(2) cert.set_subject(req.get_subject()) cert.gmtime_adj_notBefore(0) cert.gmtime_adj_notAfter(int(days) * 24 * 60 * 60) cert.set_serial_number(_new_serial(ca_name)) cert.set_issuer(ca_cert.get_subject()) cert.set_pubkey(req.get_pubkey()) cert.add_extensions(exts) cert.sign(ca_key, salt.utils.stringutils.to_str(digest)) cert_full_path = "{}/{}.crt".format(cert_path, cert_filename) with salt.utils.files.fopen(cert_full_path, "wb+") as crt: crt.write( salt.utils.stringutils.to_bytes( OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) ) ) _write_cert_to_database(ca_name, cert) return 'Created Certificate for "{}": "{}/{}.crt"'.format( CN, cert_path, cert_filename ) def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): """ Create a PKCS#12 browser certificate for a particular Certificate (CN) ca_name name of the CA CN common name matching the certificate signing request passphrase used to unlock the PKCS#12 certificate when loaded into the browser cacert_path absolute path to ca certificates root directory replace Replace this certificate even if it exists .. versionadded:: 2015.5.1 If the following values were set:: ca.cert_base_path='/etc/pki' ca_name='koji' CN='test.egavas.org' the resulting signed certificate would be written in the following location:: /etc/pki/koji/certs/test.egavas.org.p12 CLI Example: .. code-block:: bash salt '*' tls.create_pkcs12 test localhost """ set_ca_path(cacert_path) if not replace and os.path.exists( "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN) ): return 'Certificate "{}" already exists'.format(CN) try: with salt.utils.files.fopen( "{0}/{1}/{1}_ca_cert.crt".format(cert_base_path(), ca_name) ) as fhr: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: return 'There is no CA named "{}"'.format(ca_name) try: with salt.utils.files.fopen( "{}/{}/certs/{}.crt".format(cert_base_path(), ca_name, CN) ) as fhr: cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) with salt.utils.files.fopen( "{}/{}/certs/{}.key".format(cert_base_path(), ca_name, CN) ) as fhr: key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: return 'There is no certificate that matches the CN "{}"'.format(CN) pkcs12 = OpenSSL.crypto.PKCS12() pkcs12.set_certificate(cert) pkcs12.set_ca_certificates([ca_cert]) pkcs12.set_privatekey(key) with salt.utils.files.fopen( "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN), "wb" ) as ofile: ofile.write( pkcs12.export(passphrase=salt.utils.stringutils.to_bytes(passphrase)) ) return 'Created PKCS#12 Certificate for "{0}": "{1}/{2}/certs/{0}.p12"'.format( CN, cert_base_path(), ca_name, ) def cert_info(cert, digest="sha256"): """ Return information for a particular certificate cert path to the certifiate PEM file or string .. versionchanged:: 2018.3.4 digest what digest to use for fingerprinting CLI Example: .. code-block:: bash salt '*' tls.cert_info /dir/for/certs/cert.pem """ # format that OpenSSL returns dates in date_fmt = "%Y%m%d%H%M%SZ" if "-----BEGIN" not in cert: with salt.utils.files.fopen(cert) as cert_file: cert = cert_file.read() cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) issuer = {} for key, value in cert.get_issuer().get_components(): if isinstance(key, bytes): key = salt.utils.stringutils.to_unicode(key) if isinstance(value, bytes): value = salt.utils.stringutils.to_unicode(value) issuer[key] = value subject = {} for key, value in cert.get_subject().get_components(): if isinstance(key, bytes): key = salt.utils.stringutils.to_unicode(key) if isinstance(value, bytes): value = salt.utils.stringutils.to_unicode(value) subject[key] = value ret = { "fingerprint": salt.utils.stringutils.to_unicode( cert.digest(salt.utils.stringutils.to_str(digest)) ), "subject": subject, "issuer": issuer, "serial_number": cert.get_serial_number(), "not_before": calendar.timegm( time.strptime( str(cert.get_notBefore().decode(__salt_system_encoding__)), date_fmt ) ), "not_after": calendar.timegm( time.strptime( cert.get_notAfter().decode(__salt_system_encoding__), date_fmt ) ), } # add additional info if your version of pyOpenSSL supports it if hasattr(cert, "get_extension_count"): ret["extensions"] = {} for i in range(cert.get_extension_count()): try: ext = cert.get_extension(i) key = salt.utils.stringutils.to_unicode(ext.get_short_name()) ret["extensions"][key] = str(ext).strip() except AttributeError: continue if "subjectAltName" in ret.get("extensions", {}): valid_entries = ("DNS", "IP Address") valid_names = set() for name in str(ret["extensions"]["subjectAltName"]).split(", "): entry, name = name.split(":", 1) if entry not in valid_entries: log.error( "Cert %s has an entry (%s) which does not start with %s", ret["subject"], name, "/".join(valid_entries), ) else: valid_names.add(name) ret["subject_alt_names"] = list(valid_names) if hasattr(cert, "get_signature_algorithm"): try: value = cert.get_signature_algorithm() if isinstance(value, bytes): value = salt.utils.stringutils.to_unicode(value) ret["signature_algorithm"] = value except AttributeError: # On py3 at least # AttributeError: cdata 'X509 *' points to an opaque type: cannot read fields pass return ret def create_empty_crl( ca_name, cacert_path=None, ca_filename=None, crl_file=None, digest="sha256" ): """ Create an empty Certificate Revocation List. .. versionadded:: 2015.8.0 ca_name name of the CA cacert_path absolute path to ca certificates root directory ca_filename alternative filename for the CA .. versionadded:: 2015.5.3 crl_file full path to the CRL file digest The message digest algorithm. Must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1". Default: 'sha256' CLI Example: .. code-block:: bash salt '*' tls.create_empty_crl ca_name='koji' \ ca_filename='ca' \ crl_file='/etc/openvpn/team1/crl.pem' """ set_ca_path(cacert_path) if not ca_filename: ca_filename = "{}_ca_cert".format(ca_name) if not crl_file: crl_file = "{}/{}/crl.pem".format(_cert_base_path(), ca_name) if os.path.exists("{}".format(crl_file)): return 'CRL "{}" already exists'.format(crl_file) try: with salt.utils.files.fopen( "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) ) as fp_: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) with salt.utils.files.fopen( "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) ) as fp_: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) except OSError: return 'There is no CA named "{}"'.format(ca_name) crl = OpenSSL.crypto.CRL() crl_text = crl.export( ca_cert, ca_key, digest=salt.utils.stringutils.to_bytes(digest), ) with salt.utils.files.fopen(crl_file, "w") as f: f.write(salt.utils.stringutils.to_str(crl_text)) return 'Created an empty CRL: "{}"'.format(crl_file) def revoke_cert( ca_name, CN, cacert_path=None, ca_filename=None, cert_path=None, cert_filename=None, crl_file=None, digest="sha256", ): """ Revoke a certificate. .. versionadded:: 2015.8.0 ca_name Name of the CA. CN Common name matching the certificate signing request. cacert_path Absolute path to ca certificates root directory. ca_filename Alternative filename for the CA. cert_path Path to the cert file. cert_filename Alternative filename for the certificate, useful when using special characters in the CN. crl_file Full path to the CRL file. digest The message digest algorithm. Must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1". Default: 'sha256' CLI Example: .. code-block:: bash salt '*' tls.revoke_cert ca_name='koji' \ ca_filename='ca' \ crl_file='/etc/openvpn/team1/crl.pem' """ set_ca_path(cacert_path) ca_dir = "{}/{}".format(cert_base_path(), ca_name) if ca_filename is None: ca_filename = "{}_ca_cert".format(ca_name) if cert_path is None: cert_path = "{}/{}/certs".format(_cert_base_path(), ca_name) if cert_filename is None: cert_filename = "{}".format(CN) try: with salt.utils.files.fopen( "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) ) as fp_: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) with salt.utils.files.fopen( "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) ) as fp_: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) except OSError: return 'There is no CA named "{}"'.format(ca_name) client_cert = _read_cert("{}/{}.crt".format(cert_path, cert_filename)) if client_cert is None: return 'There is no client certificate named "{}"'.format(CN) index_file, expire_date, serial_number, subject = _get_basic_info( ca_name, client_cert, ca_dir ) index_serial_subject = "{}\tunknown\t{}".format(serial_number, subject) index_v_data = "V\t{}\t\t{}".format(expire_date, index_serial_subject) index_r_data_pattern = re.compile( r"R\t" + expire_date + r"\t\d{12}Z\t" + re.escape(index_serial_subject) ) index_r_data = "R\t{}\t{}\t{}".format( expire_date, _four_digit_year_to_two_digit(datetime.utcnow()), index_serial_subject, ) ret = {} with salt.utils.files.fopen(index_file) as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if index_r_data_pattern.match(line): revoke_date = line.split("\t")[2] try: datetime.strptime(revoke_date, two_digit_year_fmt) return '"{}/{}.crt" was already revoked, serial number: {}'.format( cert_path, cert_filename, serial_number ) except ValueError: ret["retcode"] = 1 ret[ "comment" ] = "Revocation date '{}' does not matchformat '{}'".format( revoke_date, two_digit_year_fmt ) return ret elif index_serial_subject in line: __salt__["file.replace"]( index_file, index_v_data, index_r_data, backup=False ) break crl = OpenSSL.crypto.CRL() with salt.utils.files.fopen(index_file) as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if line.startswith("R"): fields = line.split("\t") revoked = OpenSSL.crypto.Revoked() revoked.set_serial(salt.utils.stringutils.to_bytes(fields[3])) revoke_date_2_digit = datetime.strptime(fields[2], two_digit_year_fmt) revoked.set_rev_date( salt.utils.stringutils.to_bytes( revoke_date_2_digit.strftime(four_digit_year_fmt) ) ) crl.add_revoked(revoked) crl_text = crl.export( ca_cert, ca_key, digest=salt.utils.stringutils.to_bytes(digest) ) if crl_file is None: crl_file = "{}/{}/crl.pem".format(_cert_base_path(), ca_name) if os.path.isdir(crl_file): ret["retcode"] = 1 ret["comment"] = 'crl_file "{}" is an existing directory'.format(crl_file) return ret with salt.utils.files.fopen(crl_file, "w") as fp_: fp_.write(salt.utils.stringutils.to_str(crl_text)) return 'Revoked Certificate: "{}/{}.crt", serial number: {}'.format( cert_path, cert_filename, serial_number ) if __name__ == "__main__": # create_ca('koji', days=365, **cert_sample_meta) create_csr( "koji", CN="test_system", C="US", ST="Utah", L="Centerville", O="SaltStack", OU=None, emailAddress="test_system@saltstack.org", ) create_ca_signed_cert("koji", "test_system") create_pkcs12("koji", "test_system", passphrase="test")
Save