aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-01-10 12:56:33 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2023-01-12 15:07:57 +0100
commit0a07215d422f8f606a41d822436e6c6dd93d001f (patch)
tree3e335e7fb5e3b03b90fdef953bf7be8afef73ff8
parentConvert to pdk module. (diff)
downloadhugonikanor-letsencrypt-0a07215d422f8f606a41d822436e6c6dd93d001f.tar.gz
hugonikanor-letsencrypt-0a07215d422f8f606a41d822436e6c6dd93d001f.tar.xz
Working product.
-rw-r--r--data/Archlinux.yaml3
-rw-r--r--data/common.yaml2
-rw-r--r--data/os/Archlinux.yaml5
-rw-r--r--data/os/Debian.yaml5
-rw-r--r--data/os/FreeBSD.yaml (renamed from data/FreeBSD.yaml)0
-rw-r--r--data/os/RedHat.yaml5
-rw-r--r--data/os/RedHat/7.yaml3
-rw-r--r--files/letsencrypt-renew.service3
-rw-r--r--files/run_certbot.py35
-rw-r--r--functions/conf/nginx.pp17
-rw-r--r--functions/conf/nginx/location.pp16
-rw-r--r--hiera.yaml21
-rw-r--r--manifests/authenticator/nginx.pp22
-rw-r--r--manifests/cert.pp82
-rw-r--r--manifests/domain.pp25
-rw-r--r--manifests/init.pp65
-rw-r--r--manifests/nginx.pp52
-rw-r--r--manifests/renew.pp7
-rw-r--r--manifests/renew/cron/setup.pp (renamed from manifests/renew/cron.pp)4
-rw-r--r--manifests/renew/setup.pp19
-rw-r--r--manifests/renew/systemd.pp19
-rw-r--r--manifests/renew/systemd/setup.pp23
-rw-r--r--metadata.json2
-rw-r--r--templates/ini.epp10
-rw-r--r--types/authenticator.pp1
-rw-r--r--types/renewal_provider.pp1
-rw-r--r--types/ssl_conf/nginx.pp11
-rw-r--r--types/ssl_conf/nginx/location.pp9
28 files changed, 316 insertions, 151 deletions
diff --git a/data/Archlinux.yaml b/data/Archlinux.yaml
deleted file mode 100644
index 386801e..0000000
--- a/data/Archlinux.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-letsencrypt::nginx::certbot_plugin_package: certbot-nginx
-letsencrypt::apache::certbot_plugin_package: certbot-apache
diff --git a/data/common.yaml b/data/common.yaml
new file mode 100644
index 0000000..ae7a581
--- /dev/null
+++ b/data/common.yaml
@@ -0,0 +1,2 @@
+---
+letsencrypt::renewal_provider: cron
diff --git a/data/os/Archlinux.yaml b/data/os/Archlinux.yaml
new file mode 100644
index 0000000..671637f
--- /dev/null
+++ b/data/os/Archlinux.yaml
@@ -0,0 +1,5 @@
+---
+letsencrypt::authenticator::nginx::certbot_plugin_package: certbot-nginx
+letsencrypt::authenticator::apache::certbot_plugin_package: certbot-apache
+
+letsencrypt::renewal_provider: systemd
diff --git a/data/os/Debian.yaml b/data/os/Debian.yaml
new file mode 100644
index 0000000..0d2e358
--- /dev/null
+++ b/data/os/Debian.yaml
@@ -0,0 +1,5 @@
+---
+letsencrypt::authenticator::nginx::certbot_plugin_package: python3-certbot-nginx
+letsencrypt::authenticator::apache::certbot_plugin_package: python3-certbot-apache
+
+letsencrypt::renew::setup::provider: systemd
diff --git a/data/FreeBSD.yaml b/data/os/FreeBSD.yaml
index 6e2fe58..6e2fe58 100644
--- a/data/FreeBSD.yaml
+++ b/data/os/FreeBSD.yaml
diff --git a/data/os/RedHat.yaml b/data/os/RedHat.yaml
new file mode 100644
index 0000000..0d2e358
--- /dev/null
+++ b/data/os/RedHat.yaml
@@ -0,0 +1,5 @@
+---
+letsencrypt::authenticator::nginx::certbot_plugin_package: python3-certbot-nginx
+letsencrypt::authenticator::apache::certbot_plugin_package: python3-certbot-apache
+
+letsencrypt::renew::setup::provider: systemd
diff --git a/data/os/RedHat/7.yaml b/data/os/RedHat/7.yaml
new file mode 100644
index 0000000..0869a58
--- /dev/null
+++ b/data/os/RedHat/7.yaml
@@ -0,0 +1,3 @@
+---
+letsencrypt::authenticator::nginx::certbot_plugin_package: python2-certbot-nginx
+letsencrypt::authenticator::apache::certbot_plugin_package: python2-certbot-apache
diff --git a/files/letsencrypt-renew.service b/files/letsencrypt-renew.service
index 253f260..f8f2c18 100644
--- a/files/letsencrypt-renew.service
+++ b/files/letsencrypt-renew.service
@@ -4,5 +4,4 @@ Documentation=man:certbot(1)
[Service]
Type=oneshot
-EnvironmentFile=/etc/letsencrypt/env/%i
-ExecStart=certbot --text --agree-tos --non-interactive certonly --rsa-key-size 4086 --cert-name '%i' -a $AUTHENTICATOR $DOMAINS --post-hook $POST_HOOK --quiet --keep-until-expiring
+ExecStart=/etc/letsencrypt/renew_cert %i
diff --git a/files/run_certbot.py b/files/run_certbot.py
new file mode 100644
index 0000000..f81f707
--- /dev/null
+++ b/files/run_certbot.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+"""
+Gathers domain names to give to certbot, and then execs
+certbot. "Required" to send multiple domain names
+
+File managed by Puppet
+"""
+
+# Script should be compatible with both Python2 and Python3
+
+from __future__ import print_function
+import sys
+import os
+
+if len(sys.argv) != 2:
+ print('Takes exactly one argument: the certificates name',
+ file=sys.stderr)
+ os.exit(1)
+
+
+cert_name = sys.argv[1]
+here = os.path.dirname(sys.argv[0])
+
+cmdline = ['certbot', '--config', os.path.join(here, cert_name + ".ini")]
+with open(os.path.join(here, cert_name + '.domains')) as f:
+ for line in f:
+ if not line:
+ continue
+ if line[0] == '#':
+ continue
+ cmdline += ['-d', line.strip()]
+cmdline += ['certonly']
+
+os.execvp('certbot', cmdline)
diff --git a/functions/conf/nginx.pp b/functions/conf/nginx.pp
new file mode 100644
index 0000000..aa5f30e
--- /dev/null
+++ b/functions/conf/nginx.pp
@@ -0,0 +1,17 @@
+function letsencrypt::conf::nginx (
+ String $cert_name,
+) >> Letsencrypt::Ssl_conf::Nginx {
+ $cert_path = $facts['letsencrypt_directory'][$cert_name]
+ if $cert_path == undef {
+ {
+ ssl => false,
+ }
+ } else {
+ {
+ ssl => true,
+ ssl_redirect => true,
+ ssl_cert => "${cert_path}/fullchain.pem",
+ ssl_key => "${cert_path}/privkey.pem",
+ }
+ }
+}
diff --git a/functions/conf/nginx/location.pp b/functions/conf/nginx/location.pp
new file mode 100644
index 0000000..84d0e82
--- /dev/null
+++ b/functions/conf/nginx/location.pp
@@ -0,0 +1,16 @@
+function letsencrypt::conf::nginx::location (
+ String $cert_name,
+) >> Letsencrypt::Ssl_conf::Nginx::Location {
+ $cert_path = $facts['letsencrypt_directory'][$cert_name]
+
+ if $cert_path == undef {
+ {
+ ssl => false,
+ }
+ } else {
+ {
+ ssl => true,
+ ssl_only => true,
+ }
+ }
+}
diff --git a/hiera.yaml b/hiera.yaml
new file mode 100644
index 0000000..545fff3
--- /dev/null
+++ b/hiera.yaml
@@ -0,0 +1,21 @@
+---
+version: 5
+
+defaults: # Used for any hierarchy level that omits these keys.
+ datadir: data # This path is relative to hiera.yaml's directory.
+ data_hash: yaml_data # Use the built-in YAML backend.
+
+hierarchy:
+ - name: "osfamily/major release"
+ paths:
+ # Used to distinguish between Debian and Ubuntu
+ - "os/%{facts.os.name}/%{facts.os.release.major}.yaml"
+ - "os/%{facts.os.family}/%{facts.os.release.major}.yaml"
+ # Used for Solaris
+ - "os/%{facts.os.family}/%{facts.kernelrelease}.yaml"
+ - name: "osfamily"
+ paths:
+ - "os/%{facts.os.name}.yaml"
+ - "os/%{facts.os.family}.yaml"
+ - name: 'common'
+ path: 'common.yaml'
diff --git a/manifests/authenticator/nginx.pp b/manifests/authenticator/nginx.pp
new file mode 100644
index 0000000..971c4ed
--- /dev/null
+++ b/manifests/authenticator/nginx.pp
@@ -0,0 +1,22 @@
+# Sets up nginx specific configuration, and provides access to
+# variables for enterpolating into nginx configurations
+#
+# These use the default cert name
+# @example
+# nginx::resource::server { 'servername':
+# * => $letsescrypt::nginx::server_ssl
+# }
+# $letsencrypt::nginx::location_ssl
+# @param certbot_plugin_package
+# Name of the system package providing this plugin.
+# Populated through hiera.
+# @param manage_package
+# If this class should manage the package.
+class letsencrypt::authenticator::nginx (
+ String $certbot_plugin_package,
+ Boolean $manage_package = true,
+) {
+ if $manage_package {
+ ensure_packages([$certbot_plugin_package])
+ }
+}
diff --git a/manifests/cert.pp b/manifests/cert.pp
index 061ace1..13e1c82 100644
--- a/manifests/cert.pp
+++ b/manifests/cert.pp
@@ -1,44 +1,78 @@
# @summary A single certificate
-# TODO possibly default cert_name to $::fqdn instead
-# @param cert_name Name of the certificate
+# @param cert_name
+# Name of the certificate, can be anything, but $::fqdn is recommended
# @param ensure Present or absent (currently does nothing)
-# @param include_self Should the certificates name be one of its domains?
+# @param include_self
+# Should the certificates name be one of its domains?
+# @param authenticator
+# How should the challenge be handled.
+# @param domains
+# List of domains to add to certificate
+# @param config
+# Additional config for this entry
define letsencrypt::cert (
+ Letsencrypt::Authenticator $authenticator,
String $cert_name = $name,
Enum['present', 'absent'] $ensure = 'present',
Boolean $include_self = true,
+ Array[String] $domains = [],
+ Hash[String, Any] $config = {},
) {
- # TODO these env files are systemd specific
- # TODO concat::fragment is clumsy, look at re-implementing the
- # functionallity internally
+ $conf_file = "${letsencrypt::config_dir}/${cert_name}.ini"
+ $domain_file = "${letsencrypt::config_dir}/${cert_name}.domains"
- concat { "${letsencrypt::config_dir}/env/${cert_name}":
- ensure => present,
- warn => true,
+ include "::letsencrypt::authenticator::${authenticator}"
+
+ $local_conf = {
+ 'cert-name' => $cert_name,
+ 'rsa-key-size' => 4096,
+ 'authenticator' => $authenticator,
+ 'agree-tos' => true,
+ 'quiet' => true,
+ 'keep-until-expiring' => true,
+ 'non-interactive' => true,
}
- $cert_preamble = @(EOF)
- AUTHENTICATOR = ''
- POST_HOOK = ''
- DOMAINS =
- |- EOF
+ $conf = $letsencrypt::config_ + $local_conf + $config
- concat::fragment { "letsencrypt ${cert_name} preamble":
- target => "${letsencrypt::config_dir}/env/${cert_name}",
- order => '0',
- content => $cert_preamble,
+ file { $conf_file:
+ ensure => file,
+ content => epp("${module_name}/ini.epp", { 'values' => $conf }),
}
- concat::fragment { "letsencrypt ${cert_name} postamble":
- target => "${letsencrypt::config_dir}/env/${cert_name}",
- order => '99',
- content => "\n\n",
+ concat { $domain_file:
+ ensure_newline => true,
+ warn => true,
}
- if $include_self {
- letsencrypt::domain { $cert_name: }
+ $domains.each |$domain| {
+ letsencrypt::domain { $domain:
+ cert_name => $cert_name,
+ }
+ }
+ if $include_self and ! $cert_name in $domains {
+ letsencrypt::domain { $cert_name:
+ cert_name => $cert_name,
+ }
}
letsencrypt::renew { $cert_name:
}
+
+ # This might be incorrect. If a certificate of that name already
+ # exists then the new certificate will instead be called
+ # ${cert-name}-0001. See
+ # https://eff-certbot.readthedocs.io/en/stable/using.html#where-are-my-certificates
+ exec { "letsencrypt - get initial ${cert_name}":
+ creates => "${letsencrypt::cert_dir}/${cert_name}",
+ command => [$letsencrypt::renew::setup::renew_script, $cert_name],
+ require => File[$letsencrypt::renew::setup::renew_script],
+ }
+
+ exec { "letsencrypt - refresh ${cert_name}":
+ command => [$letsencrypt::renew::setup::renew_script, $cert_name],
+ subscribe => [File[$conf_file], Concat[$domain_file]],
+ refreshonly => true,
+ require => File[$letsencrypt::renew::setup::renew_script],
+ }
}
diff --git a/manifests/domain.pp b/manifests/domain.pp
index 9e6b377..1f9fa40 100644
--- a/manifests/domain.pp
+++ b/manifests/domain.pp
@@ -1,20 +1,15 @@
-# A single domain belonging to a certificate
-# @example
-# letsencrypt::domain { 'www.example.com':
-# cert_name => 'example.com',
-# }
-# @param domain_name Hostname which should be included in the target certificate
-# @param cert_name Certificate to add the hostname to
+# @summary
+# A single domain name which should be part of a certificate
+# @param cert_name
+# Which certificate this domain name belongs to
+# @param domain_name
+# The domain name to be added
define letsencrypt::domain (
+ String $cert_name,
String $domain_name = $name,
- String $cert_name = $::facts['fqdn'],
) {
- ensure_resource('letsencrypt::cert', $cert_name, {
- ensure => present,
- })
-
- concat::fragment { "letsencrypt ${cert_name} - ${domain_name}":
- target => "${letsencrypt::config_dir}/env/${cert_name}",
- content => " -d ${domain_name}",
+ concat::fragment { "Letsencrypt::Domain - ${cert_name} - ${domain_name}":
+ target => "${letsencrypt::config_dir}/${cert_name}.domains",
+ content => $domain_name,
}
}
diff --git a/manifests/init.pp b/manifests/init.pp
index cc72b32..d6fb5f6 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -1,38 +1,53 @@
# @summary Sets up letsencrypt for other classes
# @param email Contact email sent to letsencrypt
-# @param config_dir Location of configuration files
-# @param default_cert Should a certificate be automatically configured
-# @param default_cert_name
-# The name (and domain) of the automatically configured centificate.
+# @param manage_package
+# Should the certbot package resource be managed by this class
+# @param certbot_package
+# Name of the certbot package. Should be automatically set through hiera.
+# @param server
+# Server providing ACME challenge
+# @param renewal_provider
+# Service responsible for periodically renewing the certificate
+# @param config
+# Default configuration values to pass to certbot. $server and
+# $email is added here if not explicitly set. It's later merged with
+# a specific instance for each certificate.
class letsencrypt (
String $email,
- Stdlib::Unixpath $config_dir = '/etc/letsencrypt',
- String $default_cert_name = $::facts['fqdn'],
- Boolean $default_cert = true,
- # TODO renewal provider here?
+ Letsencrypt::Renewal_provider $renewal_provider, # hiera
+ String $certbot_package = 'certbot',
+ Boolean $manage_package = true,
+ String $server = 'https://acme-v02.api.letsencrypt.org/directory',
+ Hash[String, Any] $config = {},
) {
- if $default_cert {
- letsencrypt::cert { $default_cert_name:
- ensure => present,
- }
- }
+ # if $default_cert {
+ # letsencrypt::cert { $default_cert_name:
+ # ensure => present,
+ # }
+ # }
- file { $config_dir:
- ensure => directory,
- }
+ # These are internal instead of parameters, since certbot appears to
+ # not accept them in other places. This might prove wrong (BSD?), in
+ # that case: make them parameters again, and resolve the few remaining
+ # instances where they are hard coded.
+ $config_dir = '/etc/letsencrypt'
+ $cert_dir = "${config_dir}/live"
- $cli_conf = @("EOF")
- email = ${email}
- | EOF
+ # Used by letsencrypt::cert
+ $config_ = {
+ 'server' => $server,
+ 'email' => $email,
+ } + $config
- file { "${config_dir}/cli.ini":
- content => $cli_conf,
+ file { $config_dir:
+ ensure => directory,
}
include letsencrypt::renew::setup
- # Boolean indicating if ssl is configured. Mainly used by
- # letsencrypt::nginx and similar classes to determine their export
- # of their variable $ssl.
- $ssl_configured = 'letsencrypt_director$' in keys($facts)
+ if $manage_package {
+ package { $certbot_package:
+ ensure => installed,
+ }
+ }
}
diff --git a/manifests/nginx.pp b/manifests/nginx.pp
deleted file mode 100644
index 75b5b48..0000000
--- a/manifests/nginx.pp
+++ /dev/null
@@ -1,52 +0,0 @@
-# Sets up nginx specific configuration, and provides access to
-# variables for enterpolating into nginx configurations
-#
-# These use the default cert name
-# @example
-# nginx::resource::server { 'servername':
-# * => $letsescrypt::nginx::server_ssl
-# }
-# $letsencrypt::nginx::location_ssl
-#
-# @param certbot_plugin_package
-# Name of the system package providing this plugin.
-# Populated through hiera.
-# @param manage_package
-# If this class should manage the package.
-class letsencrypt::nginx (
- String $certbot_plugin_package,
- Boolean $manage_package = true,
-) {
- # TODO $cert_path should use the default certificate name.
- # There should however also be a hash of all configured
- # certificates.
- $cert_path = "${letsencrypt::config_dir}/live/${letsencrypt::config_dir::default_cert_name}"
-
- $server_ssl = if $letsencrypt::ssl_configured {
- {
- ssl => true,
- ssl_redirect => true,
- ssl_cert => "${cert_path}/fullchain.pem",
- ssl_key => "${cert_path}/privkey.pem",
- }
- } else {
- {
- ssl => false,
- }
- }
-
- $location_ssl = if $letsencrypt::ssl_configured {
- {
- ssl => true,
- ssl_only => true,
- }
- } else {
- {
- ssl => false,
- }
- }
-
- if $manage_package {
- ensure_packages([$certbot_plugin_package])
- }
-}
diff --git a/manifests/renew.pp b/manifests/renew.pp
index 97cf5e9..ce6fbee 100644
--- a/manifests/renew.pp
+++ b/manifests/renew.pp
@@ -6,10 +6,7 @@
define letsencrypt::renew (
String $cert_name = $name,
) {
- # TODO this is systemd specific
- # TODO ensure letsencrypt::renew::setup is included beforehand
- service { "${letsencrypt::renew::systemd::service_name}@${cert_name}.timer":
- ensure => 'running',
- enable => true,
+ Resource["letsencrypt::renew::${letsencrypt::renew::setup::provider}"] { $cert_name:
+ cert_name => $cert_name,
}
}
diff --git a/manifests/renew/cron.pp b/manifests/renew/cron/setup.pp
index 37aa3fb..d6cb51b 100644
--- a/manifests/renew/cron.pp
+++ b/manifests/renew/cron/setup.pp
@@ -1,6 +1,6 @@
# Handles renewal certificates through CRON
-# private
-class letsencrypt::renew::cron (
+# @api private
+class letsencrypt::renew::cron::setup (
) {
fail('Not yet implemented')
}
diff --git a/manifests/renew/setup.pp b/manifests/renew/setup.pp
index 8b4708b..7ba6a1b 100644
--- a/manifests/renew/setup.pp
+++ b/manifests/renew/setup.pp
@@ -1,18 +1,17 @@
# Sets up timers for automatically renewing certificates
-# TODO
-# - make provider OS dependant
-# - is provider the correct name?
# @param provider
# How the renewal should be managed.
# @api private
class letsencrypt::renew::setup (
- Enum['systemd', 'cron'] $provider = 'systemd',
+ Letsencrypt::Renewal_provider $provider = $letsencrypt::renewal_provider,
) {
- file { [
- '/etc/letsencrypt/env',
- ]:
- ensure => directory,
- }
+ include "::letsencrypt::renew::${provider}::setup"
+
+ # also used by letsencrypt::cert
+ $renew_script = "${letsencrypt::config_dir}/renew_cert"
- include "::letsencrypt::renew::${provider}"
+ file { $renew_script:
+ source => "puppet:///modules/${module_name}/run_certbot.py",
+ mode => '0555',
+ }
}
diff --git a/manifests/renew/systemd.pp b/manifests/renew/systemd.pp
index 8c63f23..f64e7e5 100644
--- a/manifests/renew/systemd.pp
+++ b/manifests/renew/systemd.pp
@@ -1,16 +1,11 @@
-# Handles renewal certificates through systemd timers
-# @param service_name Target name of the service file
-# @param service_path Where the service file should be installed
# @api private
-class letsencrypt::renew::systemd (
- String $service_name = 'letsencrypt-renew',
- String $service_path = '/etc/systemd/system',
+define letsencrypt::renew::systemd (
+ String $cert_name = $name
) {
- file { "${service_path}/${service_name}@.service":
- source => "puppet:///modules/${module_name}/letsencrypt-renew.service",
- }
-
- file { "${service_path}/${service_name}@.timer":
- source => "puppet:///modules/${module_name}/letsencrypt-renew.timer",
+ require letsencrypt::renew::systemd::setup
+ $service = $letsencrypt::renew::systemd::setup::service_name
+ service { "${service}@${cert_name}.timer":
+ ensure => 'running',
+ enable => true,
}
}
diff --git a/manifests/renew/systemd/setup.pp b/manifests/renew/systemd/setup.pp
new file mode 100644
index 0000000..5839efc
--- /dev/null
+++ b/manifests/renew/systemd/setup.pp
@@ -0,0 +1,23 @@
+# Handles renewal certificates through systemd timers
+# @param service_name Target name of the service file
+# @param service_path Where the service file should be installed
+# @api private
+class letsencrypt::renew::systemd::setup (
+ String $service_name = 'letsencrypt-renew',
+ String $service_path = '/etc/systemd/system',
+) {
+ file { "${service_path}/${service_name}@.service":
+ source => "puppet:///modules/${module_name}/letsencrypt-renew.service",
+ notify => Exec['systemctl daemon-reload'],
+ }
+
+ file { "${service_path}/${service_name}@.timer":
+ source => "puppet:///modules/${module_name}/letsencrypt-renew.timer",
+ notify => Exec['systemctl daemon-reload'],
+ }
+
+ exec { 'systemctl daemon-reload':
+ refreshonly => true,
+ provider => shell,
+ }
+}
diff --git a/metadata.json b/metadata.json
index 834628d..0416520 100644
--- a/metadata.json
+++ b/metadata.json
@@ -4,7 +4,7 @@
"author": "HugoNikanor",
"summary": "",
"license": "Apache-2.0",
- "source": "",
+ "source": "https://git.hornquist.se/puppet/hugonikanor-letsencrypt",
"operatingsystem_support": [
{
"operatingsystem": "Archlinux"
diff --git a/templates/ini.epp b/templates/ini.epp
new file mode 100644
index 0000000..7d5cc92
--- /dev/null
+++ b/templates/ini.epp
@@ -0,0 +1,10 @@
+<%- | Hash[String, Any] $values
+| -%>
+<%# This is technically not a proper ini-file, since it lacks headersa.
+ Certbot however calls them ini files, so we do to. -%>
+# File managed by Puppet
+<%- $values.each |$key, $value| { -%>
+<%- unless $value == undef { -%>
+<%= $key %> = <%= $value %>
+<%- } -%>
+<%- } -%>
diff --git a/types/authenticator.pp b/types/authenticator.pp
new file mode 100644
index 0000000..8593213
--- /dev/null
+++ b/types/authenticator.pp
@@ -0,0 +1 @@
+type Letsencrypt::Authenticator = Enum['nginx']
diff --git a/types/renewal_provider.pp b/types/renewal_provider.pp
new file mode 100644
index 0000000..bfa3077
--- /dev/null
+++ b/types/renewal_provider.pp
@@ -0,0 +1 @@
+type Letsencrypt::Renewal_provider = Enum['systemd', 'cron']
diff --git a/types/ssl_conf/nginx.pp b/types/ssl_conf/nginx.pp
new file mode 100644
index 0000000..fb2187d
--- /dev/null
+++ b/types/ssl_conf/nginx.pp
@@ -0,0 +1,11 @@
+type Letsencrypt::Ssl_conf::Nginx = Variant[
+ Struct[{
+ ssl => Boolean,
+ }],
+ Struct[{
+ ssl => Boolean,
+ ssl_redirect => Boolean,
+ ssl_cert => String,
+ ssl_key => String,
+ }],
+]
diff --git a/types/ssl_conf/nginx/location.pp b/types/ssl_conf/nginx/location.pp
new file mode 100644
index 0000000..25941d0
--- /dev/null
+++ b/types/ssl_conf/nginx/location.pp
@@ -0,0 +1,9 @@
+type Letsencrypt::Ssl_conf::Nginx::Location = Variant[
+ Struct[{
+ ssl => Boolean,
+ }],
+ Struct[{
+ ssl => Boolean,
+ ssl_only => Boolean,
+ }],
+]