diff --git a/README.md b/README.md
index 549f24d85fda7ad518a107ec5c636ecffb3a61dd..a45450ac71c88907e8b60067a33d4bdfa5cfa3ad 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,7 @@
        * [`freeradius::site`](#freeradiussite)
        * [`freeradius::sql`](#freeradiussql)
        * [`freeradius::statusclient`](#freeradiusstatusclient)
+       * [`freeradius::template`](#freeradiustemplate)
 4. [Limitations - OS compatibility, etc.](#limitations)
 5. [Development - Guide for contributing to the module](#development)
 6. [Release Notes](#release-notes)
@@ -717,6 +718,17 @@ Default: `undef`. The UDP port that this virtual server should listen on. Leave
 ##### `shortname`
 required. A short alias that is used in place of the IP address or fully qualified hostname provided in the first line of the section.
 
+#### `freeradius::template`
+
+Define template items that can be referred to in other config items
+
+##### `source`
+
+Provide source to a file with the template item. Specify only one of `source` or `content`.
+
+##### `content`
+
+Provide content of template item. Specify only one of `source` or `content`.
 
 ## Limitations
 
diff --git a/manifests/init.pp b/manifests/init.pp
index fddf66bee65be37f357f4fb1003e37c8dc9ca16c..66f0e82a52a31568da7864a442f77228938943bf 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -90,6 +90,20 @@ class freeradius (
     order   => '99',
   }
 
+  # Set up concat template file
+  concat { "${freeradius::fr_basepath}/template.conf":
+    owner   => 'root',
+    group   => $freeradius::fr_group,
+    mode    => '0640',
+    require => [Package[$freeradius::fr_package], Group[$freeradius::fr_group]],
+    notify  => Service[$freeradius::fr_service],
+  }
+  concat::fragment { 'template_header':
+    target  => "${freeradius::fr_basepath}/template.conf",
+    content => "# Template config\n\n",
+    order   => '05',
+  }
+
   # Set up concat proxy file
   concat { "${freeradius::fr_basepath}/proxy.conf":
     owner   => 'root',
diff --git a/manifests/template.pp b/manifests/template.pp
new file mode 100644
index 0000000000000000000000000000000000000000..d2f86e62eed115d112e1714ab121a8bdf06856e2
--- /dev/null
+++ b/manifests/template.pp
@@ -0,0 +1,16 @@
+# Configure a template snippet
+define freeradius::template (
+  $source,
+  $content,
+) {
+  $fr_basepath = $::freeradius::params::fr_basepath
+
+  # Configure config fragment for this template
+  concat::fragment { "template -${name}":
+    target  => "${fr_basepath}/template.conf",
+    source  => $source,
+    content => $content,
+    order   => 10,
+  }
+}
+
diff --git a/templates/radiusd.conf.fr2.erb b/templates/radiusd.conf.fr2.erb
index cc5fa92027b87f93124efc150d1a01daf58a1f43..c52f60d756887f8a0dd42407cce1ee4f8256aa26 100644
--- a/templates/radiusd.conf.fr2.erb
+++ b/templates/radiusd.conf.fr2.erb
@@ -828,6 +828,14 @@ instantiate {
 	$INCLUDE instantiate/
 }
 
+######################################################################
+#
+#  Enable support for templates
+#
+######################################################################
+$INCLUDE templates.conf
+
+
 ######################################################################
 #
 #	Policies that can be applied in multiple places are listed
diff --git a/templates/radiusd.conf.fr3.erb b/templates/radiusd.conf.fr3.erb
index f72ee47ef6c93e9799c578a28acbde113760ab2f..9e3b1f4c758a779320a4ec39c2687593eaba6b3f 100644
--- a/templates/radiusd.conf.fr3.erb
+++ b/templates/radiusd.conf.fr3.erb
@@ -722,6 +722,12 @@ instantiate {
 	#}
 }
 
+######################################################################
+#
+#  Enable support for templates
+#
+$INCLUDE templates.conf
+
 ######################################################################
 #
 #  Policies are virtual modules, similar to those defined in the