Imported from simp/pupmod-simp-simp_apache (
AGENTS.md). Install upstream withnpx skills add simp/pupmod-simp-simp_apache. Copyright stays with the author.
AGENTS.md
This file provides guidance to AI agents when working with code in this repository.
What this module does
simp-simp_apache is a SIMP Puppet module that installs and configures an
Apache (httpd) web server hardened to SIMP conventions. It manages the
httpd package(s), lays down httpd.conf and the SSL configuration from
templates, creates the apache user/group, manages the SELinux booleans Apache
needs, optionally rsyncs the web root from a SIMP rsync server, and wires Apache
into the surrounding SIMP feature modules (iptables, rsyslog, PKI, haveged).
This is an older, legacy module: its own metadata.json summary flags it as
"legacy, conflicts with puppetlabs-apache," and the docstring on
manifests/init.pp states the long-term intent is to migrate to the
Puppet Labs apache module. It carries hand-rolled ERB templates, a custom
htaccess type/provider, and helper functions rather than delegating to a
maintained upstream Apache module. Treat it as a maintenance target: prefer
minimal, surgical changes over rewrites.
The module is structured as an orchestrating entry class (simp_apache) that
includes a small set of component classes (install, conf, service, and
optionally ssl), plus a site define for dropping in per-site vhost configs.
Business logic
-
simp_apache(manifests/init.pp) — Public entry class; consumersinclude 'simp_apache'. It callssimplib::assert_metadata($module_name)and thenincludessimp_apache::install,simp_apache::conf, andsimp_apache::service. When$sslis true (default) it alsoincludessimp_apache::ssl. Key parameters (init.pp):$data_dir(Stdlib::AbsolutePath, default/var/www) — where web data lives. (The docstring says/srv/www"for legacy reasons," but the code default is/var/www; trust the code.)$ssl(Boolean, defaulttrue) — master switch for the SSL class.$rsync_source(String) — defaults to"apache_${environment}_${os.name}/www".$rsync_server(Simplib::Host) —simp_options::rsync::server, default127.0.0.1.$rsync_timeout(Integer) —simp_options::rsync::timeout, default2.$rsync_web_root(Boolean, defaulttrue) — whether to rsync the web root.
Resources and control flow:
- Ordering (
init.pp):installruns beforesimp_apache,conf, and (when enabled)ssl;installandconfbothnotifyservice. group { 'apache' }anduser { 'apache' }are pinned to uid/gid 48 withallowdupe => false,shell => /sbin/nologin, home/usr/share/httpd, andmembership => minimum(init.pp).- rsync branch (
init.pp): when$rsync_web_root,include 'rsync'and declarersync { 'site' }pulling$rsync_sourceto/var, with the per-host rsync password sourced fromsimplib::passgen(...)(init.pp) anddelete => false. - SELinux branch (
init.pp): only when the SELinux mode fact is set and notdisabled, sets fourselbooleans persistently on:httpd_verify_dns,allow_ypbind,allow_httpd_mod_auth_pam,httpd_can_network_connect.
-
simp_apache::install(manifests/install.pp) — Private class (assert_private()atinstall.pp). Managespackage { 'httpd' }, andpackage { 'mod_ssl' }only when$simp_apache::sslis true (install.pp). All three ensure params ($httpd_ensure,$mod_ldap_ensure,$mod_ssl_ensure) default tosimp_options::package_ensure→'installed'. -
simp_apache::conf(manifests/conf.pp) — Renders/etc/httpd/conf/httpd.conffrom an ERB template (conf.pp), manages theconf/conf.ddirectories (withpurge => $purge, defaulttrue— this purges unmanaged files), themagicfile (EPP,replace => false), a symlink farm (/etc/httpd/logs,/etc/httpd/modules,/etc/httpd/run), and the$data_dir. The modules symlink target is arch-dependent:/usr/lib64/httpd/modulesonx86_64, else/usr/lib/httpd/modules(conf.pp). Networks in$allowrootare normalized throughsimp_apache::munge_httpd_networks()(conf.pp). This class carries the bulk of the tunables (prefork/worker MPM sizing, keepalive, logging, etc.).- firewall branch (
conf.pp): when$firewall,include 'iptables'and open the$listenports (default[80]) viaiptables::listen::tcp_statefulwithtrusted_nets => $l_allowroot. - syslog branch (
conf.pp): when$syslog,include '::rsyslog'and add tworsyslog::rule::localrules routinghttpderror and access logs under$syslog_target(default/var/log/httpd).
- firewall branch (
-
simp_apache::service(manifests/service.pp) — Managesservice { 'httpd' }(ensure => running,enable => true) only when$manage(defaulttrue). If$hasrestartis false (the default), a custom$restartcommand is used that triessystemctl reloadthen falls back torestart(service.pp). When$manageis false you may need to add the service tosvckill::ignore(per the docstring). -
simp_apache::ssl(manifests/ssl.pp) — Renders/etc/httpd/conf.d/ssl.conffrom ERB (ssl.pp), notifying the service. Optionallyinclude 'haveged'(ssl.pp) andinclude 'iptables'to open the SSL$listenports (default[443]). When$pkiis truthy,pki::copy { 'simp_apache' }manages certs under/etc/pki/simp_apps/simp_apache/x509(ssl.pp). Defaults:$ssl_protocols = ['TLSv1.2'],$sslverifyclient = 'require',$sslverifydepth = 10,$ssl_honor_cipher_order = true. -
simp_apache::site(manifests/site.pp) — Define. Drops a/etc/httpd/conf.d/${name}.conffile,notifying the service. With the default$content = 'base'it renders atemplates/sites/${name}.conf.erbtemplate; otherwise$contentis written verbatim (site.pp). File owner/group come frompick($simp_apache::conf::user/group, ...). -
simp_apache::validate(manifests/validate.pp) — Not a resource class; it just defines$method_acl, a nested hash of regex/validation rules intended as input tovalidate_deep_hashwhen managingldap/limitsACLs.
Gotchas / non-obvious details
simp_apache::confpurges by default.$purgedefaults totrue(conf.pp), which setspurge/forceon/etc/httpd/confand/etc/httpd/conf.d(conf.pp). Any httpd config file not managed by this module (or dropped in viasimp_apache::site) will be removed. This is the single most surprising behavior — setsimp_apache::conf::purge: falsein Hiera if consumers manage config files out-of-band.- The
apacheuser/group are hard-pinned to uid/gid 48 (init.pp) withallowdupe => false— a collision with an existing uid/gid 48 will fail the run. - The rsync password comes from
simplib::passgen(init.pp), so the rsync branch depends on SIMP's passgen infrastructure being available and seeded; the server side must accept that generated credential. $sslis read across classes.installgatesmod_sslon$simp_apache::ssl(install.pp) andsite/sslread$simp_apache::conf::user/groupviapick(...)— the component classes are tightly coupled through the top-level class's variables, so they are not meant to beincluded standalone in isolation fromsimp_apache.- SELinux booleans are only touched when SELinux is enabled (
init.pp); on adisabled/absent SELinux host they are silently skipped. simp/simp_optionsis NOT a declared dependency inmetadata.json, yet everysimplib::lookup('simp_options::*', ...)call reads that seam (simplib::lookupis provided bysimp/simplib).simp_optionsappears only as a.fixtures.ymlfixture for test compilation.- This module conflicts with
puppetlabs-apache(permetadata.jsonsummary). Do not attempt to co-managehttpdwith both. - The modules symlink target is arch-gated (
conf.pp); non-x86_64hosts get/usr/lib/httpd/modules.
The simp_options / simplib::lookup seam
This is the module's real business-logic seam (the natural target for a
lookup-path unit test). All calls route SIMP feature toggles through
simplib::lookup('simp_options::*', { 'default_value' => ... }):
| Location | Key | default_value |
|---|---|---|
init.pp |
simp_options::rsync::server |
'127.0.0.1' |
init.pp |
simp_options::rsync::timeout |
2 |
install.pp |
simp_options::package_ensure (×3) |
'installed' |
conf.pp |
simp_options::firewall |
false |
conf.pp |
simp_options::syslog |
false |
ssl.pp |
simp_options::trusted_nets |
['127.0.0.1', '::1'] |
ssl.pp |
simp_options::openssl::cipher_suite |
['DEFAULT', '!MEDIUM'] |
ssl.pp |
simp_options::pki |
false |
ssl.pp |
simp_options::pki::source |
'/etc/pki/simp/x509' |
ssl.pp |
simp_options::firewall |
false |
ssl.pp |
simp_options::haveged |
false |
Keep routing SIMP feature toggles through simplib::lookup('simp_options::*', { 'default_value' => ... }) with an explicit default rather than assuming
simp_options is included. There are no simplib::assert_optional_dependency
calls in this module — every integration (iptables, rsyslog, pki,
haveged, rsync) is a hard, declared dependency toggled by a simp_options
flag.
Dependencies
Module dependencies (from metadata.json) — all hard, no optional dependencies:
simp/simplib>= 4.9.0 < 5.0.0(providessimplib::lookup,simplib::assert_metadata,simplib::passgen,simplib::nets2cidr, and theSimplib::*data types used throughout)simp/haveged>= 0.4.5 < 1.0.0(entropy, via the SSL class)simp/iptables>= 6.5.3 < 8.0.0(firewall rules)simp/logrotate>= 6.5.0 < 7.0.0simp/pki>= 6.2.0 < 7.0.0(pki::copyfor certs)simp/rsync>= 6.1.1 < 7.0.0(web-root sync)simp/rsyslog>= 7.6.0 < 9.0.0(log routing)simp/auditd>= 8.5.0 < 9.0.0puppetlabs/stdlib>= 8.0.0 < 10.0.0(pick()and friends)
Runtime requirement (from metadata.json requirements): `puppet
= 7.0.0 < 9.0.0
. (SIMP is migrating Puppet → OpenVox; this module still namespuppetand itsGemfileinstalls only thepuppetgem. Whenmetadata.jsonswitches this toopenvox`, update this line to match.)
Supported OS matrix (from metadata.json): CentOS 7/8/9; RedHat 7/8/9;
OracleLinux 7/8/9; Rocky 8/9; AlmaLinux 8/9.
Repository layout
manifests/init.pp—simp_apache, the orchestrating entry class.manifests/install.pp—simp_apache::install(private): packages.manifests/conf.pp—simp_apache::conf:httpd.conf, dirs, symlinks, firewall/syslog branches; carries most tunables.manifests/service.pp—simp_apache::service: thehttpdservice.manifests/ssl.pp—simp_apache::ssl:ssl.conf, PKI, haveged, HTTPS firewall.manifests/site.pp—simp_apache::sitedefine: per-site vhost configs.manifests/validate.pp—simp_apache::validate: the$method_aclvalidation-rule hash (no resources).types/logseverity.pp—Simp_apache::LogSeverity, anEnumof Apache log levels used byconf.pp.lib/facter/apache_version.rb— custom factapache_version(parsesapachectl -v; returns'unknown'if undeterminable).lib/puppet/type/htaccess.rb+lib/puppet/provider/htaccess/htaccess.rb— customhtaccesstype/provider managing htpasswd-style files (namevar ispath:username).lib/puppet/functions/simp_apache/— three Ruby v4 functions:auth(builds Apache auth directives from a hash),limits(buildsLimit/OrderACL directives), andmunge_httpd_networks(normalizes networks to Apache form, e.g.0.0.0.0/0→ALL).templates/etc/httpd/conf/httpd.conf.erb,.../conf.d/ssl.conf.erb,.../conf/magic.epp— the config templates.metadata.json— deps, OS matrix, Puppet requirement.spec/classes/{init,conf,ssl}_spec.rb,spec/defines/site_spec.rb— rspec-puppet unit tests;spec/classes/expected/httpd.conf_default_el{7,8,9}are golden-file comparisons of the renderedhttpd.conf.spec/functions/simp_apache/*_spec.rb,spec/unit/puppet/{type,provider}/— unit tests for the functions and thehtaccesstype/provider.spec/acceptance/suites/{default,htaccess}/— beaker suites;spec/acceptance/nodesets/{default,oel}.yml— nodesets.- No
data/orhiera.yaml— this module ships no module-level Hiera data; all defaults are inline in the manifests. - Acceptance does NOT run in CI:
.github/workflows/pr_tests.ymlhas six jobs only —puppet-syntax,puppet-style,ruby-style,file-checks,releng-checks, andspec-tests(a Puppet-version matrix). There is noacceptance/beaker job and noBEAKER_HYPERVISORin CI; the nodesets exist for local acceptance runs only.
Common commands
# Install dependencies
bundle install
# Run all unit tests
bundle exec rake spec
# Run a single spec
bundle exec rspec spec/classes/init_spec.rb
# Puppet lint
bundle exec rake lint
# Ruby lint
bundle exec rake rubocop
# Regenerate REFERENCE.md from puppet-strings docstrings
puppet strings generate --format markdown --out REFERENCE.md
# Run the default beaker acceptance suite (local only — not run in CI)
bundle exec rake beaker:suites[default]
Relevant gem pins (from Gemfile): puppetlabs_spec_helper ~> 8.0.0,
simp-rake-helpers ~> 5.24.0, simp-rspec-puppet-facts ~> 4.0.0,
simp-beaker-helpers ~> 2.0.0. Rubocop is pinned to ~> 1.88.0. The Gemfile
defaults puppet_version to ['>= 7', '< 9'] and installs the puppet gem
(no openvox gem). spec/spec_helper.rb requires
puppetlabs_spec_helper/module_spec_helper.
Conventions
- Preserve the
@summary/@parampuppet-strings docstrings on the classes, the define, and the functions — they driveREFERENCE.md. RegenerateREFERENCE.mdafter changing docs or parameters. - Keep routing SIMP feature toggles through
simplib::lookup('simp_options::*', { 'default_value' => ... })with an explicit default rather than assumingsimp_optionsis included. - Keep
simp_apache::installassert_private()'d — it is an implementation detail ofsimp_apache, not a public entry point. - Respect the component-class coupling:
install/conf/service/sslread top-levelsimp_apachevariables and each other's params — declare them via thesimp_apacheorchestration, not standalone. - Be careful with
simp_apache::conf::purge(defaulttrue): new config files must be managed by the module (orsimp_apache::site) or they will be purged. Gemfile,spec/spec_helper.rb, and.github/workflows/pr_tests.ymlcarry a puppetsync notice — they are baseline-managed and the next sync overwrites local edits. Push changes to those files upstream to the baseline, not here.- Match the existing 2-space Puppet indentation and aligned-arrow / aligned-
=parameter style used acrossmanifests/. - This is a legacy module intended to eventually migrate to
puppetlabs-apache(init.pp) — favor minimal, targeted fixes over large refactors.