diff --git a/manifests/ca/intermediate.pp b/manifests/ca/intermediate.pp
new file mode 100644
index 0000000000000000000000000000000000000000..303e71c09f030efd4df75c8d7e4933d835755ace
--- /dev/null
+++ b/manifests/ca/intermediate.pp
@@ -0,0 +1,63 @@
+# @summary A short summary of the purpose of this defined type.
+#
+# A description of what this defined type does
+#
+# @example
+#   cfssl::ca::intermediate { 'namevar': }
+define cfssl::ca::intermediate (
+  Hash $subject = { 'C' => 'FR', 'L' => 'MONTPELLIER', 'O' => 'EXEMPLE ORG', },
+  String[1] $expiry = '26280h',
+  Cfssl::Ca::Key $key = { algo => 'rsa', size => 2048 },
+) {
+  require cfssl::ca::root
+
+  $_rootca_name = regsubst($cfssl::ca::root::cn, '\s', '', 'G')
+  $_rootca_cert = "${cfssl::confdir}/ca/${_rootca_name}.pem"
+  $_rootca_privkey = "${cfssl::confdir}/ca/${_rootca_name}-key.pem"
+
+  $_intermediatecn = $name
+  $_intermediateca_name = regsubst($name, '\s', '', 'G')
+  $_intermediateca_csr = {
+    cn    => $_intermediatecn,
+    names => [$subject],
+    key   => $key,
+  }
+  $_intermediateca_csr_json = to_json($_intermediateca_csr)
+
+  $_root_to_intermediate_config = {
+    signing => {
+      'default' => {
+        expiry        => $expiry,
+        ca_constraint => {
+          is_ca        => true,
+          max_path_len => 1,
+        },
+        usages        => [
+          'cert sign',
+          'crl sign',
+        ],
+      },
+    },
+  }
+  $_root_to_intermediate_config_file = "${cfssl::confdir}/ca/root-to-intermediate-${_intermediateca_name}_config.json"
+
+  file { $_root_to_intermediate_config_file:
+    ensure  => file,
+    mode    => '0600',
+    owner   => $cfssl::sysuser,
+    group   => $cfssl::sysgroup,
+    content => to_json_pretty($_root_to_intermediate_config),
+  }
+  -> exec { "genkey ${_intermediatecn}":
+    path    => "/usr/bin:${cfssl::binpath}",
+    command => "echo '${_intermediateca_csr_json}' | cfssl genkey - | cfssljson -bare ${cfssl::confdir}/ca/${_intermediateca_name}",
+    creates => "${cfssl::confdir}/ca/${_intermediateca_name}-key.pem",
+    user    => $cfssl::sysuser,
+  }
+  -> exec { "${cfssl::ca::root::cn} sign ${_intermediatecn} csr":
+    path    => "/usr/bin:${cfssl::binpath}",
+    command => "cfssl sign -ca ${_rootca_cert} -ca-key ${_rootca_privkey} -config ${_root_to_intermediate_config_file} ${cfssl::confdir}/ca/${_intermediateca_name}.csr | cfssljson -bare ${cfssl::confdir}/ca/${_intermediateca_name}",
+    creates => "${cfssl::confdir}/ca/${_intermediateca_name}.pem",
+    user    => $cfssl::sysuser,
+  }
+}
diff --git a/manifests/ca/intermediates.pp b/manifests/ca/intermediates.pp
new file mode 100644
index 0000000000000000000000000000000000000000..4269d89f27088dd504ccc50e8df6643a061d06ee
--- /dev/null
+++ b/manifests/ca/intermediates.pp
@@ -0,0 +1,15 @@
+# @summary A short summary of the purpose of this class
+#
+# A description of what this class does
+#
+# @example
+#   include cfssl::ca::intermediates
+class cfssl::ca::intermediates (
+  Hash $intermediates = {},
+) {
+  $intermediates.each | String[1] $_cn , Hash $_intermediate_manifest | {
+    cfssl::ca::intermediate { $_cn:
+      * => $_intermediate_manifest,
+    }
+  }
+}
diff --git a/manifests/ca/root.pp b/manifests/ca/root.pp
index b323aa44a711f0aba864412a92c29517cd99b885..4bf94421f9046f5f519312fff721fcf52f3a93d3 100644
--- a/manifests/ca/root.pp
+++ b/manifests/ca/root.pp
@@ -6,11 +6,12 @@
 #   include cfssl::ca::root
 #
 class cfssl::ca::root (
-  Hash $subject = { 'C' => 'FR', 'L' => 'MONTPELLIER', 'O' => 'EXEMPLE ORG', 'OU' => 'IT Dept' },
-  String[1] $cn = 'EXEMPLE ROOT CA GEN1',
+  Hash $subject,
+  String[1] $cn,
   String[1] $expiry = '43800h',
   Cfssl::Ca::Key $key = { algo => 'rsa', size => 2048 },
 ) {
+  $_rootca_name = regsubst($cn, '\s', '', 'G')
   $_rootca_csr = {
     cn    => $cn,
     names => [$subject],
@@ -21,8 +22,8 @@ class cfssl::ca::root (
 
   exec { "initca ${cn}":
     path    => "/usr/bin:${cfssl::binpath}",
-    command => "echo '${_rootca_csr_json}' | cfssl gencert -initca - | cfssljson -bare ${cfssl::confdir}/ca/${cfssl::serve_ca}",
-    creates => "${cfssl::confdir}/ca/${cfssl::serve_ca}-key.pem",
+    command => "echo '${_rootca_csr_json}' | cfssl gencert -initca - | cfssljson -bare ${cfssl::confdir}/ca/${_rootca_name}",
+    creates => "${cfssl::confdir}/ca/${_rootca_name}-key.pem",
     user    => $cfssl::sysuser,
   }
 }
diff --git a/manifests/init.pp b/manifests/init.pp
index 506b18ff026ac51c7c5a63fda3644b9994dcdd82..bdc5dcb6418ffa9e2a9f705db141266eb3b7180c 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -8,7 +8,7 @@
 # @param crl_expiry A value, in seconds, after which the CRL should expire from the moment of the request
 #
 class cfssl (
-  Hash $rootca_manifest = {},
+  Hash $rootca_manifest = { cn => 'EXEMPLE ROOT CA', subject => { 'C' => 'FR', 'L' => 'MONTPELLIER', 'O' => 'EXEMPLE ORG', } },
   Stdlib::HTTPSUrl $downloadurl = 'https://github.com/cloudflare/cfssl/releases/download',
   String[1] $version = '1.6.3',
   String[1] $downloadchecksum = '16b42bfc592dc4d0ba1e51304f466cae7257edec13743384caf4106195ab6047',
@@ -25,11 +25,12 @@ class cfssl (
   Stdlib::Absolutepath $confdir = '/etc/cfssl',
   Stdlib::Absolutepath $binpath = '/usr/local/bin',
   Cfssl::Serveconfig $serve_config = { signing => { 'default' => { expiry => '1h', usages => ['client auth'] } } },
-  String[1] $serve_ca = 'ROOT_ca',
-  Boolean $crl_manage = true,
+  Boolean $crl_manage = false,
   Stdlib::Absolutepath $crldir = '/var/cfssl',
   Integer $crl_expiry = 604800,
   String[1] $crl_gentimer = '*:00:00',
+  Hash $intermediatesca = {},
+  Optional[String[1]] $serve_ca = undef,
 ) {
   include cfssl::goose
   include postgresql::server
@@ -151,70 +152,94 @@ class cfssl (
     ],
   }
 
-  file { $_systemd_unit_file:
-    ensure  => file,
-    mode    => '0644',
-    owner   => 0,
-    group   => 0,
-    content => epp('cfssl/cfssl.service.epp'),
-  }
-  ~> service { 'cfssl':
-    ensure    => 'running',
-    enable    => true,
-    require   => [
-      Archive["${binpath}/cfssl"],
-      Postgresql::Server::Db[$dbname],
-      Exec['goose pg up'],
-      File["${confdir}/${_serve_config_json}"],
-      File["${confdir}/${_db_config_json}"],
-      Class['cfssl::ca::root'],
-    ],
-    subscribe => Archive["${binpath}/cfssl"],
-    provider  => 'systemd',
+  if $intermediatesca {
+    class { 'cfssl::ca::intermediates':
+      intermediates => $intermediatesca,
+    }
   }
 
-  if $cfssl::crl_manage {
-    ensure_packages(['jq','coreutils'], { ensure => 'present' })
-
-    file { "${cfssl::binpath}/cfssl-gencrl.sh":
+  if $serve_ca {
+    file { $_systemd_unit_file:
       ensure  => file,
-      mode    => '0755',
+      mode    => '0644',
       owner   => 0,
       group   => 0,
-      content => epp('cfssl/cfssl-gencrl.sh.epp'),
+      content => epp('cfssl/cfssl.service.epp'),
     }
+    ~> service { 'cfssl':
+      ensure    => 'running',
+      enable    => true,
+      require   => [
+        Archive["${binpath}/cfssl"],
+        Postgresql::Server::Db[$dbname],
+        Exec['goose pg up'],
+        File["${confdir}/${_serve_config_json}"],
+        File["${confdir}/${_db_config_json}"],
+        Class['cfssl::ca::root'],
+      ],
+      subscribe => Archive["${binpath}/cfssl"],
+      provider  => 'systemd',
+    }
+
+    if $cfssl::crl_manage {
+      ensure_packages(['jq','coreutils'], { ensure => 'present' })
 
-    $_crlunits.each | String $_crlunit | {
-      file { "${_systemd_unitdir}/${_crlunit}":
+      file { "${cfssl::binpath}/cfssl-gencrl.sh":
         ensure  => file,
-        mode    => '0644',
+        mode    => '0755',
         owner   => 0,
         group   => 0,
-        content => epp("cfssl/${$_crlunit}.epp"),
+        content => epp('cfssl/cfssl-gencrl.sh.epp'),
       }
-      ~> service { $_crlunit:
-        ensure   => 'running',
-        enable   => true,
-        require  => [
-          File["${cfssl::binpath}/cfssl-gencrl.sh"],
-          Service['cfssl'],
-        ],
-        provider => 'systemd',
+
+      $_crlunits.each | String $_crlunit | {
+        file { "${_systemd_unitdir}/${_crlunit}":
+          ensure  => file,
+          mode    => '0644',
+          owner   => 0,
+          group   => 0,
+          content => epp("cfssl/${$_crlunit}.epp"),
+        }
+        ~> service { $_crlunit:
+          ensure    => 'running',
+          enable    => true,
+          require   => [
+            File["${cfssl::binpath}/cfssl-gencrl.sh"],
+            Service['cfssl'],
+          ],
+          subscribe => Service['cfssl'],
+          provider  => 'systemd',
+        }
       }
-    }
-  } else {
-    $_crlunits.each | String $_crlunit | {
-      service { $_crlunit:
-        ensure   => 'stopped',
-        enable   => false,
-        provider => 'systemd',
+    } else {
+      $_crlunits.each | String $_crlunit | {
+        service { $_crlunit:
+          ensure   => 'stopped',
+          enable   => false,
+          provider => 'systemd',
+        }
+        -> file { "${_systemd_unitdir}/${_crlunit}":
+          ensure  => absent,
+        }
       }
-      -> file { "${_systemd_unitdir}/${_crlunit}":
+      file { "${cfssl::binpath}/cfssl-gencrl.sh":
         ensure  => absent,
       }
     }
-    file { "${cfssl::binpath}/cfssl-gencrl.sh":
-      ensure  => absent,
+  } else {
+    service { 'cfssl':
+      ensure    => 'stopped',
+      enable    => false,
+      require   => [
+        Archive["${binpath}/cfssl"],
+        Postgresql::Server::Db[$dbname],
+        Exec['goose pg up'],
+        File["${confdir}/${_serve_config_json}"],
+        File["${confdir}/${_db_config_json}"],
+        Class['cfssl::ca::root'],
+      ],
+      subscribe => Archive["${binpath}/cfssl"],
+      provider  => 'systemd',
     }
   }
 }
diff --git a/spec/acceptance/cfssl_spec.rb b/spec/acceptance/cfssl_spec.rb
index fc6130374e1a105f65505a9684e42c5139d00c88..2f057072043da97cf914b0d3dae73eefd211fcf0 100644
--- a/spec/acceptance/cfssl_spec.rb
+++ b/spec/acceptance/cfssl_spec.rb
@@ -13,6 +13,39 @@ describe 'cfssl' do
       apply_manifest(pp, catch_changes: true)
     end
 
+    describe command('openssl x509 -in /etc/cfssl/ca/EXEMPLEROOTCA.pem -text -noout') do
+      # rubocop:disable RSpec/RepeatedDescription
+      its(:stdout) { is_expected.to match %r{Certificate:} }
+      its(:stdout) { is_expected.to match %r{Issuer: C = FR, L = MONTPELLIER, O = EXEMPLE ORG, CN = EXEMPLE ROOT CA} }
+      its(:stdout) { is_expected.to match %r{Subject: C = FR, L = MONTPELLIER, O = EXEMPLE ORG, CN = EXEMPLE ROOT CA} }
+      its(:stdout) { is_expected.to match %r{CA:TRUE} }
+      # rubocop:enable RSpec/RepeatedDescription
+    end
+  end
+
+  context 'with served root ca' do
+    pp = %(
+      class { 'cfssl':
+        rootca_manifest => {
+          cn      => 'MYEXEMPLE ROOT CA',
+          subject => {
+            'C' => 'FR',
+            'L' => 'MONTPELLIER',
+            'O' => 'MYEXEMPLE ORG',
+          },
+        },
+        serve_ca        => 'MYEXEMPLE ROOT CA',
+        crl_manage      => true,
+      }
+    )
+
+    it 'applies without error' do
+      apply_manifest(pp, catch_failures: true)
+    end
+    it 'applies idempotently' do
+      apply_manifest(pp, catch_changes: true)
+    end
+
     describe port(8080) do
       it { is_expected.to be_listening.on('127.0.0.1').with('tcp') }
     end
@@ -20,11 +53,76 @@ describe 'cfssl' do
     describe command('curl -s -d "{}" -H "Content-Type: application/json" -X POST 127.0.0.1:8080/api/v1/cfssl/info') do
       its(:stdout) { is_expected.to match %r{BEGIN CERTIFICATE} }
     end
+
+    describe command('openssl x509 -in /etc/cfssl/ca/MYEXEMPLEROOTCA.pem -text -noout') do
+      # rubocop:disable RSpec/RepeatedDescription
+      its(:stdout) { is_expected.to match %r{Certificate:} }
+      its(:stdout) { is_expected.to match %r{Issuer: C = FR, L = MONTPELLIER, O = MYEXEMPLE ORG, CN = MYEXEMPLE ROOT CA} }
+      its(:stdout) { is_expected.to match %r{Subject: C = FR, L = MONTPELLIER, O = MYEXEMPLE ORG, CN = MYEXEMPLE ROOT CA} }
+      its(:stdout) { is_expected.to match %r{CA:TRUE} }
+    end
+
     describe command('openssl crl -in /var/cfssl/crl.pem -text -noout') do
+      its(:stdout) { is_expected.to match %r{Certificate Revocation List } }
+      its(:stdout) { is_expected.to match %r{Issuer: C = FR, L = MONTPELLIER, O = MYEXEMPLE ORG, CN = MYEXEMPLE ROOT CA} }
+      its(:stdout) { is_expected.to match %r{No Revoked Certificates} }
+      # rubocop:enable RSpec/RepeatedDescription
+    end
+  end
+
+  context 'with served intermediate ca' do
+    pp = %(
+      class { 'cfssl':
+        rootca_manifest => {
+          cn      => 'MYEXEMPLE ROOT CA',
+          subject => {
+            'C' => 'FR',
+            'L' => 'MONTPELLIER',
+            'O' => 'MYEXEMPLE ORG',
+          },
+        },
+        intermediatesca => {
+          'MYEXEMPLE INTERMDIATE CA' => {
+            subject => {
+              'C' => 'FR',
+              'L' => 'MONTPELLIER',
+              'O' => 'MYEXEMPLE ORG',
+            },
+          },
+        },
+        serve_ca   => 'MYEXEMPLE INTERMDIATE CA',
+        crl_manage => true,
+      }
+    )
+
+    it 'applies without error' do
+      apply_manifest(pp, catch_failures: true)
+    end
+    it 'applies idempotently' do
+      apply_manifest(pp, catch_changes: true)
+    end
+
+    describe port(8080) do
+      it { is_expected.to be_listening.on('127.0.0.1').with('tcp') }
+    end
+
+    describe command('curl -s -d "{}" -H "Content-Type: application/json" -X POST 127.0.0.1:8080/api/v1/cfssl/info') do
+      its(:stdout) { is_expected.to match %r{BEGIN CERTIFICATE} }
+    end
+
+    describe command('openssl x509 -in /etc/cfssl/ca/MYEXEMPLEINTERMDIATECA.pem -text -noout') do
       # rubocop:disable RSpec/RepeatedDescription
+      its(:stdout) { is_expected.to match %r{Certificate:} }
+      its(:stdout) { is_expected.to match %r{Issuer: C = FR, L = MONTPELLIER, O = MYEXEMPLE ORG, CN = MYEXEMPLE ROOT CA} }
+      its(:stdout) { is_expected.to match %r{Subject: C = FR, L = MONTPELLIER, O = MYEXEMPLE ORG, CN = MYEXEMPLE INTERMDIATE CA} }
+      its(:stdout) { is_expected.to match %r{CA:TRUE, pathlen:1} }
+    end
+
+    describe command('openssl crl -in /var/cfssl/crl.pem -text -noout') do
       its(:stdout) { is_expected.to match %r{Certificate Revocation List } }
-      its(:stdout) { is_expected.to match %r{Issuer: C = FR, L = MONTPELLIER, O = EXEMPLE ORG, OU = IT Dept, CN = EXEMPLE ROOT CA GEN1} }
+      its(:stdout) { is_expected.to match %r{Issuer: C = FR, L = MONTPELLIER, O = MYEXEMPLE ORG, CN = MYEXEMPLE INTERMDIATE CA} }
       its(:stdout) { is_expected.to match %r{No Revoked Certificates} }
+      # rubocop:enable RSpec/RepeatedDescription
     end
   end
 end
diff --git a/spec/classes/ca/intermediates_spec.rb b/spec/classes/ca/intermediates_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5f1ab6c221003b224cdd1f24c4b6e04d3b37cdac
--- /dev/null
+++ b/spec/classes/ca/intermediates_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'cfssl::ca::intermediates' do
+  on_supported_os.each do |os, os_facts|
+    context "on #{os}" do
+      let(:facts) { os_facts }
+
+      it { is_expected.to compile }
+    end
+  end
+end
diff --git a/spec/defines/ca/intermediate_spec.rb b/spec/defines/ca/intermediate_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..934446ba37577b6c950362a69999e0f1706c0a97
--- /dev/null
+++ b/spec/defines/ca/intermediate_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'cfssl::ca::intermediate' do
+  let(:title) { 'namevar' }
+  let(:pre_condition) do
+    <<-PRECOND
+    require postgresql::server
+    include cfssl
+    PRECOND
+  end
+
+  on_supported_os.each do |os, os_facts|
+    context "on #{os}" do
+      let(:facts) { os_facts.merge(service_provider: 'systemd') }
+
+      it { is_expected.to compile }
+    end
+  end
+end
diff --git a/templates/ca-root-to-intermediate-config.json.epp b/templates/ca-root-to-intermediate-config.json.epp
new file mode 100644
index 0000000000000000000000000000000000000000..3fb8c2ec301f4f70b61e8a7d53781f3ae78f978f
--- /dev/null
+++ b/templates/ca-root-to-intermediate-config.json.epp
@@ -0,0 +1,15 @@
+{
+  "signing": {
+    "default": {
+      "expiry": "70080h",
+      "ca_constraint": {
+        "is_ca": true,
+        "max_path_len": 1,
+      },
+      "usages": [
+        "cert sign",
+        "crl sign",
+      ]
+    }
+  }
+}
diff --git a/templates/cfssl.service.epp b/templates/cfssl.service.epp
index f568d8bd6141c6a061b661cb2f0081d5136bdd0e..f49b637c5606733e3560f81172b29a55deee870d 100644
--- a/templates/cfssl.service.epp
+++ b/templates/cfssl.service.epp
@@ -6,7 +6,7 @@ After=network-online.target
 [Service]
 User=<%= $cfssl::sysuser %>
 Group=<%= $cfssl::sysgroup %>
-ExecStart=<%= $cfssl::binpath %>/cfssl -log_dir <%= $cfssl::logdir %> serve -address <%= $cfssl::binding_ip %> -ca <%= $cfssl::confdir %>/ca/<%= $cfssl::serve_ca %>.pem -ca-key <%= $cfssl::confdir %>/ca/<%= $cfssl::serve_ca %>-key.pem -port <%= $cfssl::port %> -db-config <%= $cfssl::confdir %>/db-config.json -config <%= $cfssl::confdir %>/serve-config.json -loglevel <%= $cfssl::log_level %>
+ExecStart=<%= $cfssl::binpath %>/cfssl -log_dir <%= $cfssl::logdir %> serve -address <%= $cfssl::binding_ip %> -ca <%= $cfssl::confdir %>/ca/<%= regsubst($cfssl::serve_ca, '\s', '', 'G') %>.pem -ca-key <%= $cfssl::confdir %>/ca/<%= regsubst($cfssl::serve_ca, '\s', '', 'G')  %>-key.pem -port <%= $cfssl::port %> -db-config <%= $cfssl::confdir %>/db-config.json -config <%= $cfssl::confdir %>/serve-config.json -loglevel <%= $cfssl::log_level %>
 Restart=always
 PrivateTmp=yes
 ProtectSystem=full