Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebuild Foreman infrastructure #1777

Merged
merged 9 commits into from Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Expand Up @@ -27,6 +27,8 @@ jobs:
unzip g10k-linux-amd64.zip
- name: Install modules using g10k
run: ./g10k -cachedir .g10k/cache -puppetfile
- name: Verify dependencies are compatible
run: bundle exec ./check_dependencies
- name: Run syntax
run: bundle exec rake syntax
- name: Run lint
Expand Down
10 changes: 5 additions & 5 deletions Vagrantfile
Expand Up @@ -8,7 +8,7 @@ Vagrant.configure("2") do |config|
config.vm.provision "install puppet", type: "shell", inline: <<-SHELL
. /etc/os-release
yum -y install epel-release
yum -y install puppet6-release || yum -y install https://yum.puppetlabs.com/puppet6/puppet6-release-el-${VERSION_ID}.noarch.rpm
yum -y install puppet7-release || yum -y install https://yum.puppetlabs.com/puppet7/puppet7-release-el-${VERSION_ID}.noarch.rpm
yum -y install puppet-agent
SHELL

Expand Down Expand Up @@ -59,8 +59,8 @@ Vagrant.configure("2") do |config|
end
override.vm.provision "install puppet", type: "shell", inline: <<-SHELL
. /etc/os-release
wget https://apt.puppet.com/puppet6-release-${VERSION_CODENAME}.deb
apt-get install -y ./puppet6-release-${VERSION_CODENAME}.deb
wget https://apt.puppet.com/puppet7-release-${VERSION_CODENAME}.deb
apt-get install -y ./puppet7-release-${VERSION_CODENAME}.deb
apt-get update
apt-get install -y puppet-agent
SHELL
Expand All @@ -75,8 +75,8 @@ Vagrant.configure("2") do |config|
end
override.vm.provision "install puppet", type: "shell", inline: <<-SHELL
. /etc/os-release
wget https://apt.puppet.com/puppet6-release-${VERSION_CODENAME}.deb
apt-get install -y ./puppet6-release-${VERSION_CODENAME}.deb
wget https://apt.puppet.com/puppet7-release-${VERSION_CODENAME}.deb
apt-get install -y ./puppet7-release-${VERSION_CODENAME}.deb
apt-get update
apt-get install -y puppet-agent
SHELL
Expand Down
61 changes: 61 additions & 0 deletions docs/bootstrap.md
@@ -0,0 +1,61 @@
# Boostrap a new environment

To rebuild the whole Foreman Infrastructure from scratch, these are the steps to get started.

## Build a Puppetserver

Install a minimal EL8 install. Then:

```sh
dnf install https://yum.puppet.com/puppet7-release-el-8.noarch.rpm
dnf install puppetserver
. /etc/profile.d/puppet-agent.sh
puppetserver ca setup --ca-name 'Foreman Puppet CA' --certname $HOSTNAME --subject-alt-names puppet.theforeman.org
puppet config set --section agent server puppet.theforeman.org
puppet config set --section main dns_alt_names puppet.theforeman.org
evgeni marked this conversation as resolved.
Show resolved Hide resolved
# To allow the foreman node a SAN
sed -i '/allow-subject-alt-names/ s/false/true/' /etc/puppetlabs/puppetserver/conf.d/ca.conf
Comment on lines +16 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate a bit on this? You want to build a foreman01.$hoster.theforeman.org with a SAN of foreman.theforeman.org and need this setting to allow it?

Please be aware that someone (cough) found that this can open up a rather big can of worms (nothing checks the SAN when signing) and is thus not recommended by Puppet: "Be aware that enabling the setting could allow agent nodes to impersonate other nodes (including the nodes that already have signed certificates). Consequently, you must carefully inspect any CSRs with SANs attached."

Especially, Foreman doesn't show any SANs at all in the signing UI.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I guess we can enable that, sign the cert for foreman.tfm.o and disable it again?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right about that. The alternative I thought about was using Let's Encrypt for a proper URL. Tricky part there is access to it. Right now I have set up a firewall to only allow port 443 from the Puppetserver and my home network. I guess we could set up rules so that it does IP checks in Apache for everything except /.well-known or use DNS validation, but that's a lot trickier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd go with the easiest option, which to me seems to be "enable, sign, disable, (forget it 5 years)"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll opt to keep this in bootstrap for now, then when Puppet actually runs it should be disabled again.

systemctl enable --now puppetserver puppet
firewall-cmd --add-port 8140/tcp
firewall-cmd --add-port 8140/tcp --permanent
mkdir /etc/puppetlabs/code/environments/bootstrap
chown YOURUSER: /etc/puppetlabs/code/environments/bootstrap
```

With a basic Puppetserver running, deploy the environment. From your local machine:

```
# Download the latest from https://github.com/xorpaul/g10k/releases and place it in ~/bin
git clone https://github.com/theforeman/foreman-infra
cd foreman-infra/puppet
g10k -cachedir ~/.cache/.g10k -puppetfile
rsync -av --delete --exclude={Gem,Rake,Puppet}file*,test_modules,spec,check_dependencies ./ SERVER.EXAMPLE.COM:/etc/puppetlabs/code/environments/bootstrap/
```

## Build a Foreman server

Install a minimal EL8 install. Then:

```sh
dnf install https://yum.puppet.com/puppet7-release-el-8.noarch.rpm
dnf install puppet-agent
. /etc/profile.d/puppet-agent.sh
puppet config set --section agent environment bootstrap
puppet config set --section agent server puppet.theforeman.org
puppet config set --section main dns_alt_names foreman.theforeman.org
puppet ssl bootstrap
systemctl enable --now puppet
```

In case it should become a production setup, import the database dump:
```
puppet agent --disable
systemctl stop foreman\* dynflow\*
sudo -u postgres dropdb foreman
sudo -u postgres createdb -O foreman foreman
sudo -u postgres psql foreman < /path/to/dump.sql
foreman-rake db:migrate
foreman-rake db:seed
puppet agent --enable
puppet agent -t
```
20 changes: 0 additions & 20 deletions docs/foreman-puppetserver.md

This file was deleted.

10 changes: 10 additions & 0 deletions docs/foreman.md
@@ -0,0 +1,10 @@
# Foreman

| | foreman01.conova.theforeman.org |
| - | - |
| type | Libvirt VM |
| OS | CentOS Stream 8 |
| CPUs | 4 |
| RAM | 4GB |
| Storage | /dev/vda (20GB) |
| Managed by | [profiles::foreman](https://github.com/theforeman/foreman-infra/blob/master/puppet/modules/profiles/manifests/foreman.pp) |
3 changes: 2 additions & 1 deletion docs/index.md
Expand Up @@ -18,10 +18,11 @@ Fork https://github.com/theforeman/foreman-infra and add your key into the [file
| Role | Provider(s) |
|---|---|
| [Discourse](discourse.md) | Scaleway |
| [Foreman](foreman-puppetserver.md) | Scaleway |
| [Foreman](foreman.md) | Conova |
| [Koji](koji.md) | AWS |
| [Jenkins](jenkins.md) | OSUOSL |
| [Jenkins Nodes](jenkins.md) | OSUOSL / AWS / Conova / Netways |
| [Puppet](puppet.md) | Conova |
| [Redmine](redmine.md) | Scaleway |
| [Virt](virt.md) | Conova |
| [Webserver](webserver.md) | OSUOSL |
Expand Down
4 changes: 2 additions & 2 deletions docs/jenkins.md
Expand Up @@ -53,7 +53,7 @@ https://github.com/theforeman/foreman-infra/tree/master/puppet/modules contains
For Enterprise Linux:

* Ensure EPEL is configured: [epel-release](https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm)
* Ensure yum.puppet.com is configured: [puppet6-release](https://yum.puppet.com/puppet6/puppet6-release-el-7.noarch.rpm)
* Ensure yum.puppet.com is configured: [puppet7-release](https://yum.puppet.com/puppet7-release-el-7.noarch.rpm)
* `yum -y install puppet-agent`
* `echo "server = puppetmaster.theforeman.org" >> /etc/puppetlabs/puppet/puppet.conf`
* ensure hostname is set node0X.jenkins.<provider\>.theforeman.org where <provider> is osuosl or aws for example and that the record is in DNS
Expand All @@ -67,7 +67,7 @@ For Enterprise Linux:

For Debian:

* Ensure apt.puppet.com is configured: [puppet6-release](https://apt.puppetlabs.com/puppet6-release-buster.deb)
* Ensure apt.puppet.com is configured: [puppet7-release](https://apt.puppetlabs.com/puppet7-release-bullseye.deb)
* `apt update && apt install puppet-agent`
* `echo "server = puppetmaster.theforeman.org" >> /etc/puppetlabs/puppet/puppet.conf`
* Make the `puppet` command available: `source /etc/profile.d/puppet-agent.sh`
Expand Down
10 changes: 10 additions & 0 deletions docs/puppet.md
@@ -0,0 +1,10 @@
# Puppetserver

| | puppet01.conova.theforeman.org |
| - | - |
| type | Libvirt VM |
| OS | CentOS Stream 8 |
| CPUs | 4 |
| RAM | 8GB |
| Storage | /dev/vda (20GB) |
| Managed by | [profiles::puppetserver](https://github.com/theforeman/foreman-infra/blob/master/puppet/modules/profiles/manifests/puppetserver.pp) |
2 changes: 1 addition & 1 deletion docs/virt.md
Expand Up @@ -37,7 +37,7 @@ systemctl enable --now libvirtd

Now bootstrap Puppet:
```
dnf install https://yum.puppet.com/puppet6-release-el-8.noarch.rpm
dnf install https://yum.puppet.com/puppet7-release-el-8.noarch.rpm
dnf install puppet-agent
. /etc/profile.d/puppet-agent.sh
puppet config set server puppetmaster.theforeman.org
Expand Down
4 changes: 3 additions & 1 deletion mkdocs.yml
Expand Up @@ -4,10 +4,12 @@ nav:
- Overview: index.md
- Roles:
- Discourse: discourse.md
- Foreman: foreman-puppetserver.md
- Foreman: foreman.md
- Jenkins: jenkins.md
- Koji: koji.md
- Puppet: puppet.md
- Redmine: redmine.md
- Virt: virt.md
- Webserver: webserver.md
- GPG: gpg.md
- Bootstrap: bootstrap.md
5 changes: 4 additions & 1 deletion puppet/Gemfile
@@ -1,6 +1,9 @@
source 'https://rubygems.org'

gem 'puppet', '~> 6.9', require: false
gem 'puppet_metadata'
gem 'semantic_puppet'

gem 'puppet', '~> 7.0', require: false
gem 'puppet-lint', require: false
gem 'puppet-lint-absolute_classname-check', require: false
gem 'puppet-lint-classes_and_types_beginning_with_digits-check', require: false
Expand Down
12 changes: 7 additions & 5 deletions puppet/Puppetfile
Expand Up @@ -15,11 +15,12 @@ mod 'puppet/jenkins', '3.0.0'
mod 'puppet/letsencrypt', '8.0.2'
mod 'puppet/nodejs', '8.0.0'
mod 'puppet/pbuilder', '1.0.0'
mod 'puppet/redis', '8.4.0'
mod 'puppet/rvm', '2.0.0'
mod 'puppet/selinux', '3.1.0'
mod 'puppet/systemd', '3.10.0'
mod 'puppet/unattended_upgrades', '6.0.0'
mod 'puppetlabs/apache', '5.4.0'
mod 'puppetlabs/apache', '7.0.0'
mod 'puppetlabs/apt', '7.7.0'
mod 'puppetlabs/concat', '6.2.0 '
mod 'puppetlabs/inifile', '4.1.0 '
Expand All @@ -37,11 +38,12 @@ mod 'puppetlabs/translate', '2.2.0'
mod 'puppetlabs/vcsrepo', '3.1.0'
mod 'puppetlabs/xinetd', '3.3.0'
mod 'richardc/datacat', '0.6.2'
mod 'saz/sudo', '6.0.0'
mod 'theforeman/foreman', '13.1.0'
mod 'theforeman/foreman_proxy', '12.1.0'
mod 'saz/sudo', '7.0.2'
mod 'theforeman/foreman', '19.3.0'
mod 'theforeman/foreman_proxy', '21.0.0'
mod 'theforeman/git', '6.0.1'
mod 'theforeman/motd', '0.1.0'
mod 'theforeman/puppet', '12.0.1'
mod 'theforeman/puppet', '16.3.0'
mod 'theforeman/puppetserver_foreman', '2.0.0'
mod 'theforeman/tftp', '5.0.1'
mod 'treydock/yum_cron', '6.2.0'
134 changes: 134 additions & 0 deletions puppet/check_dependencies
@@ -0,0 +1,134 @@
#!/usr/bin/env ruby

require 'puppet_metadata'
require 'semantic_puppet'

def normalize_name(name)
name.tr('-', '/')
end

class LocalModules < SemanticPuppet::Dependency::Source
attr_reader :modules

def initialize(module_dirs)
@modules = {}

module_dirs.each do |module_dir|
Dir[File.join(module_dir, '*', 'metadata.json')].sort.map do |metadata|
mod = PuppetMetadata.read(metadata)
dependencies = mod.dependencies.map { |name, requirement| [normalize_name(name), requirement.to_s] }
name = normalize_name(mod.name)
@modules[name] = create_release(name, mod.version, dependencies)
rescue PuppetMetadata::InvalidMetadataException => e
raise "#{metadata}: #{e}"
end
end

@modules.freeze
end

def fetch(name)
if @modules.key?(name)
[@modules[name]]
else
[]
end
end
end

class ProvidedModules < SemanticPuppet::Dependency::Source
attr_reader :modules

def initialize(modules)
@modules = {}

modules.each do |name, version|
name = normalize_name(name)
@modules[name] = create_release(name, version)
end

@modules.freeze
end

def fetch(name)
if @modules.key?(name)
[@modules[name]]
else
[]
end
end
end

# TODO: read this from environment.conf
local_source = LocalModules.new(['modules', 'external_modules'])
SemanticPuppet::Dependency.add_source(local_source)

# TODO: Read this from a file
# These should be soft dependencies
provided = {
'puppet/zypprepo' => '3.1.0', # puppet/jenkins
'theforeman/dhcp' => '8.0.0', # theforeman/foreman_proxy
'theforeman/dns' => '9.0.0', # theforeman/foreman_proxy
}
provided_source = ProvidedModules.new(provided)
SemanticPuppet::Dependency.add_source(provided_source)

modules = Hash[local_source.modules.map { |name, mod| [name, mod.version.to_s] }]

graph = SemanticPuppet::Dependency.query(modules)
begin
releases = SemanticPuppet::Dependency.resolve(graph)
puts "Satisfied all dependencies:"
releases.each do |release|
# TODO: print source
puts " #{release.name} #{release.version}"
end
rescue SemanticPuppet::Dependency::UnsatisfiableGraph => e
# There was some dependency that wasn't matched. We know its name and that
# it's a dependency we requested previously. Now to investigate why to
# provide useful hints

# TODO: it's *very* weird to store unsatisfiable in a module
# Strange API
unsatisfiable = SemanticPuppet::Dependency.unsatisfiable

unless unsatisfiable
# In older semantic_puppet unsatisfiable was unreliable
# Needs https://github.com/puppetlabs/semantic_puppet/pull/37
$stderr.puts e
$stderr.puts "semantic_puppet provides insufficient information to hint why"
exit 1
end

$stderr.puts "Unable to satisfy #{unsatisfiable}"

releases = graph.dependencies[unsatisfiable]
if releases.empty?
# This should never happen
$stderr.puts "No releases found for #{unsatisfiable}"
exit 2
end

releases.each do |release|
$stderr.puts "Investigating version #{release.version}"
unsatisfied = release.dependencies.select { |_, candidates| candidates.empty? }
if unsatisfied.empty?
# Is this ever the case, did we miss anything else?
$stderr.puts " All dependencies satisfied"
else
unsatisfied.each do |dependency, _|
constraint = release.constraints_for(dependency).find { |constraint| constraint[:source] == 'initialize' }
$stderr.puts " Dependency #{dependency} (#{constraint[:description]}) can't be satified"

constraint_graph = SemanticPuppet::Dependency.query(dependency => '>= 0')
begin
releases = SemanticPuppet::Dependency.resolve(constraint_graph)
mod_releases = releases.select { |release| release.name == dependency }
$stderr.puts " Available versions: #{mod_releases.map { |r| r.version }.join(', ')}"
rescue SemanticPuppet::Dependency::UnsatisfiableGraph
$stderr.puts " Unable to find any release"
end
end
end
end
end