Merge branch 'joeyconfig'

Conflicts:
	privdata.joey/privdata.gpg
This commit is contained in:
Joey Hess 2015-02-12 12:35:26 -04:00
commit cb67eb1d08
15 changed files with 331 additions and 161 deletions

View File

@ -19,7 +19,6 @@ import qualified Propellor.Property.Dns as Dns
import qualified Propellor.Property.OpenId as OpenId import qualified Propellor.Property.OpenId as OpenId
import qualified Propellor.Property.Docker as Docker import qualified Propellor.Property.Docker as Docker
import qualified Propellor.Property.Git as Git import qualified Propellor.Property.Git as Git
import qualified Propellor.Property.Apache as Apache
import qualified Propellor.Property.Postfix as Postfix import qualified Propellor.Property.Postfix as Postfix
import qualified Propellor.Property.Grub as Grub import qualified Propellor.Property.Grub as Grub
import qualified Propellor.Property.Obnam as Obnam import qualified Propellor.Property.Obnam as Obnam
@ -27,7 +26,6 @@ import qualified Propellor.Property.Gpg as Gpg
import qualified Propellor.Property.Systemd as Systemd import qualified Propellor.Property.Systemd as Systemd
import qualified Propellor.Property.Journald as Journald import qualified Propellor.Property.Journald as Journald
import qualified Propellor.Property.OS as OS import qualified Propellor.Property.OS as OS
import qualified Propellor.Property.HostingProvider.DigitalOcean as DigitalOcean
import qualified Propellor.Property.HostingProvider.CloudAtCost as CloudAtCost import qualified Propellor.Property.HostingProvider.CloudAtCost as CloudAtCost
import qualified Propellor.Property.HostingProvider.Linode as Linode import qualified Propellor.Property.HostingProvider.Linode as Linode
import qualified Propellor.Property.SiteSpecific.GitHome as GitHome import qualified Propellor.Property.SiteSpecific.GitHome as GitHome
@ -47,6 +45,7 @@ hosts = -- (o) `
, kite , kite
, diatom , diatom
, elephant , elephant
, beaver
] ++ monsters ] ++ monsters
testvm :: Host testvm :: Host
@ -86,7 +85,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64"
& Ssh.randomHostKeys & Ssh.randomHostKeys
& Apt.unattendedUpgrades & Apt.unattendedUpgrades
& Network.ipv6to4 & Network.ipv6to4
& Tor.isBridge & Tor.named "kite1" Tor.isRelay'
& Postfix.satellite & Postfix.satellite
& Docker.configured & Docker.configured
@ -118,8 +117,8 @@ orca = standardSystem "orca.kitenet.net" Unstable "amd64"
& Docker.docked (GitAnnexBuilder.standardAutoBuilderContainer dockerImage "amd64" 15 "2h") & Docker.docked (GitAnnexBuilder.standardAutoBuilderContainer dockerImage "amd64" 15 "2h")
& Docker.docked (GitAnnexBuilder.standardAutoBuilderContainer dockerImage "i386" 45 "2h") & Docker.docked (GitAnnexBuilder.standardAutoBuilderContainer dockerImage "i386" 45 "2h")
& Docker.docked (GitAnnexBuilder.armelCompanionContainer dockerImage) & Docker.docked (GitAnnexBuilder.armelCompanionContainer dockerImage)
& Docker.docked (GitAnnexBuilder.armelAutoBuilderContainer dockerImage "1 3 * * *" "5h") & Docker.docked (GitAnnexBuilder.armelAutoBuilderContainer dockerImage (Cron.Times "1 3 * * *") "5h")
& Docker.docked (GitAnnexBuilder.androidAutoBuilderContainer dockerImage "1 1 * * *" "3h") & Docker.docked (GitAnnexBuilder.androidAutoBuilderContainer dockerImage (Cron.Times "1 1 * * *") "3h")
& Docker.garbageCollected `period` Daily & Docker.garbageCollected `period` Daily
& Apt.buildDep ["git-annex"] `period` Daily & Apt.buildDep ["git-annex"] `period` Daily
@ -128,7 +127,7 @@ orca = standardSystem "orca.kitenet.net" Unstable "amd64"
-- with propellor. -- with propellor.
kite :: Host kite :: Host
kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64" kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
[ "Welcome to the new kitenet.net server!" ] [ "Welcome to kite!" ]
& ipv4 "66.228.36.95" & ipv4 "66.228.36.95"
& ipv6 "2600:3c03::f03c:91ff:fe73:b0d2" & ipv6 "2600:3c03::f03c:91ff:fe73:b0d2"
& alias "kitenet.net" & alias "kitenet.net"
@ -143,6 +142,7 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& Network.static "eth0" `requires` Network.cleanInterfacesFile & Network.static "eth0" `requires` Network.cleanInterfacesFile
& Apt.installed ["linux-image-amd64"] & Apt.installed ["linux-image-amd64"]
& Linode.chainPVGrub 5 & Linode.chainPVGrub 5
& Linode.mlocateEnabled
& Apt.unattendedUpgrades & Apt.unattendedUpgrades
& Systemd.installed & Systemd.installed
& Systemd.persistentJournal & Systemd.persistentJournal
@ -150,7 +150,7 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& Ssh.passwordAuthentication True & Ssh.passwordAuthentication True
-- Since ssh password authentication is allowed: -- Since ssh password authentication is allowed:
& Apt.serviceInstalledRunning "fail2ban" & Apt.serviceInstalledRunning "fail2ban"
& Obnam.backupEncrypted "/" "33 1 * * *" & Obnam.backupEncrypted "/" (Cron.Times "33 1 * * *")
[ "--repository=sftp://joey@eubackup.kitenet.net/~/lib/backup/kite.obnam" [ "--repository=sftp://joey@eubackup.kitenet.net/~/lib/backup/kite.obnam"
, "--client-name=kitenet.net" , "--client-name=kitenet.net"
, "--exclude=/var/cache" , "--exclude=/var/cache"
@ -171,12 +171,18 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& alias "mail.kitenet.net" & alias "mail.kitenet.net"
& JoeySites.kiteMailServer & JoeySites.kiteMailServer
& alias "ns4.kitenet.net" & JoeySites.kitenetHttps
& myDnsSecondary
& alias "ns4.branchable.com"
& branchableSecondary
& JoeySites.legacyWebSites & JoeySites.legacyWebSites
& File.ownerGroup "/srv/web" "joey" "joey"
& Apt.installed ["analog"]
& alias "git.kitenet.net"
& alias "git.joeyh.name"
& JoeySites.gitServer hosts
& JoeySites.downloads hosts
& JoeySites.gitAnnexDistributor
& JoeySites.tmp
& alias "bitlbee.kitenet.net" & alias "bitlbee.kitenet.net"
& Apt.serviceInstalledRunning "bitlbee" & Apt.serviceInstalledRunning "bitlbee"
@ -201,73 +207,32 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& Docker.configured & Docker.configured
& Docker.garbageCollected `period` Daily & Docker.garbageCollected `period` Daily
& Docker.docked oldusenetShellBox ! Docker.docked oldusenetShellBox
diatom :: Host
diatom = standardSystem "diatom.kitenet.net" (Stable "wheezy") "amd64"
[ "Important stuff that needs not too much memory or CPU." ]
& ipv4 "107.170.31.195"
& Ssh.hostKeys hostContext
[ (SshDsa, "ssh-dss AAAAB3NzaC1kc3MAAACBAO9tnPUT4p+9z7K6/OYuiBNHaij4Nzv5YVBih1vMl+ALz0gYAj8RWJzXmqp5buFAyfgOoLw+H9s1bBS01Sy3i07Dm6cx1fWG4RXL/E/3w1tavX99GD2bBxDBu890ebA5Tp+eFRJkS9+JwSvFiF6CP7NbVjifCagoUO56Ig048RwDAAAAFQDPY2xM3q6KwsVQliel23nrd0rV2QAAAIEAga3hj1hL00rYPNnAUzT8GAaSP62S4W68lusErH+KPbsMwFBFY/Ib1FVf8k6Zn6dZLh/HH/RtJi0JwdzPI1IFW+lwVbKfwBvhQ1lw9cH2rs1UIVgi7Wxdgfy8gEWxf+QIqn62wG+Ulf/HkWGvTrRpoJqlYRNS/gnOWj9Z/4s99koAAACBAM/uJIo2I0nK15wXiTYs/NYUZA7wcErugFn70TRbSgduIFH6U/CQa3rgHJw9DCPCQJLq7pwCnFH7too/qaK+czDk04PsgqV0+Jc7957gU5miPg50d60eJMctHV4eQ1FpwmGGfXxRBR9k2ZvikWYatYir3L6/x1ir7M0bA9IzNU45")
, (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA2QAJEuvbTmaN9ex9i9bjPhMGj+PHUYq2keIiaIImJ+8mo+yKSaGUxebG4tpuDPx6KZjdycyJt74IXfn1voGUrfzwaEY9NkqOP3v6OWTC3QeUGqDCeJ2ipslbEd9Ep9XBp+/ldDQm60D0XsIZdmDeN6MrHSbKF4fXv1bqpUoUILk=")
]
& DigitalOcean.distroKernel
& Apt.unattendedUpgrades
& Apt.serviceInstalledRunning "ntp"
& Postfix.satellite
-- Diatom has 500 mb of memory, so tune for that.
& JoeySites.obnamLowMem
& Apt.serviceInstalledRunning "swapspace"
& Apt.serviceInstalledRunning "apache2"
& JoeySites.kitenetHttps
& Apache.multiSSL
& File.ownerGroup "/srv/web" "joey" "joey"
& Apt.installed ["analog"]
& alias "git.kitenet.net"
& alias "git.joeyh.name"
& JoeySites.gitServer hosts
& JoeySites.annexWebSite "/srv/git/downloads.git"
"downloads.kitenet.net"
"840760dc-08f0-11e2-8c61-576b7e66acfd"
[("eubackup", "ssh://eubackup.kitenet.net/~/lib/downloads/")]
`requires` Ssh.keyImported SshRsa "joey" (Context "downloads.kitenet.net")
`requires` Ssh.knownHost hosts "eubackup.kitenet.net" "joey"
& JoeySites.gitAnnexDistributor
& JoeySites.annexWebSite "/srv/git/joey/tmp.git"
"tmp.kitenet.net"
"26fd6e38-1226-11e2-a75f-ff007033bdba"
[]
& JoeySites.twitRss
& JoeySites.pumpRss
& JoeySites.annexWebSite "/srv/git/user-liberation.git"
"user-liberation.joeyh.name"
"da89f112-808b-420a-b468-d990ae2e5b52"
[]
& alias "nntp.olduse.net" & alias "nntp.olduse.net"
& alias "resources.olduse.net"
& JoeySites.oldUseNetServer hosts & JoeySites.oldUseNetServer hosts
& alias "ns2.kitenet.net" & alias "ns4.kitenet.net"
& myDnsPrimary True "kitenet.net" [] & myDnsPrimary True "kitenet.net" []
& myDnsPrimary True "joeyh.name" [] & myDnsPrimary True "joeyh.name" []
& myDnsPrimary True "ikiwiki.info" [] & myDnsPrimary True "ikiwiki.info" []
& myDnsPrimary True "olduse.net" & myDnsPrimary True "olduse.net"
[ (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk") [ (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk")
] ]
& alias "ns4.branchable.com"
& alias "ns3.branchable.com"
& branchableSecondary & branchableSecondary
& Dns.secondaryFor ["animx"] hosts "animx.eu.org" & Dns.secondaryFor ["animx"] hosts "animx.eu.org"
diatom :: Host
diatom = standardSystem "diatom.kitenet.net" (Stable "wheezy") "amd64"
[ "dying" ]
& ipv4 "107.170.31.195"
& Ssh.hostKeys hostContext
[ (SshDsa, "ssh-dss AAAAB3NzaC1kc3MAAACBAO9tnPUT4p+9z7K6/OYuiBNHaij4Nzv5YVBih1vMl+ALz0gYAj8RWJzXmqp5buFAyfgOoLw+H9s1bBS01Sy3i07Dm6cx1fWG4RXL/E/3w1tavX99GD2bBxDBu890ebA5Tp+eFRJkS9+JwSvFiF6CP7NbVjifCagoUO56Ig048RwDAAAAFQDPY2xM3q6KwsVQliel23nrd0rV2QAAAIEAga3hj1hL00rYPNnAUzT8GAaSP62S4W68lusErH+KPbsMwFBFY/Ib1FVf8k6Zn6dZLh/HH/RtJi0JwdzPI1IFW+lwVbKfwBvhQ1lw9cH2rs1UIVgi7Wxdgfy8gEWxf+QIqn62wG+Ulf/HkWGvTrRpoJqlYRNS/gnOWj9Z/4s99koAAACBAM/uJIo2I0nK15wXiTYs/NYUZA7wcErugFn70TRbSgduIFH6U/CQa3rgHJw9DCPCQJLq7pwCnFH7too/qaK+czDk04PsgqV0+Jc7957gU5miPg50d60eJMctHV4eQ1FpwmGGfXxRBR9k2ZvikWYatYir3L6/x1ir7M0bA9IzNU45")
, (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA2QAJEuvbTmaN9ex9i9bjPhMGj+PHUYq2keIiaIImJ+8mo+yKSaGUxebG4tpuDPx6KZjdycyJt74IXfn1voGUrfzwaEY9NkqOP3v6OWTC3QeUGqDCeJ2ipslbEd9Ep9XBp+/ldDQm60D0XsIZdmDeN6MrHSbKF4fXv1bqpUoUILk=")
]
& alias "ns2.kitenet.net"
elephant :: Host elephant :: Host
elephant = standardSystem "elephant.kitenet.net" Unstable "amd64" elephant = standardSystem "elephant.kitenet.net" Unstable "amd64"
[ "Storage, big data, and backups, omnomnom!" [ "Storage, big data, and backups, omnomnom!"
@ -294,7 +259,6 @@ elephant = standardSystem "elephant.kitenet.net" Unstable "amd64"
& JoeySites.obnamRepos ["wren", "pell", "kite"] & JoeySites.obnamRepos ["wren", "pell", "kite"]
& JoeySites.githubBackup & JoeySites.githubBackup
& JoeySites.rsyncNetBackup hosts & JoeySites.rsyncNetBackup hosts
& JoeySites.backupsBackedupTo hosts "usbackup.kitenet.net" "lib/backup/eubackup"
& alias "podcatcher.kitenet.net" & alias "podcatcher.kitenet.net"
& JoeySites.podcatcher & JoeySites.podcatcher
@ -328,6 +292,18 @@ elephant = standardSystem "elephant.kitenet.net" Unstable "amd64"
-- block 22. -- block 22.
& Ssh.listenPort 80 & Ssh.listenPort 80
beaver :: Host
beaver = host "beaver.kitenet.net"
& ipv6 "2001:4830:1600:195::2"
& Apt.serviceInstalledRunning "aiccu"
& Apt.installed ["ssh"]
& Ssh.pubKey SshDsa "ssh-dss AAAAB3NzaC1kc3MAAACBAIrLX260fY0Jjj/p0syNhX8OyR8hcr6feDPGOj87bMad0k/w/taDSOzpXe0Wet7rvUTbxUjH+Q5wPd4R9zkaSDiR/tCb45OdG6JsaIkmqncwe8yrU+pqSRCxttwbcFe+UU+4AAcinjVedZjVRDj2rRaFPc9BXkPt7ffk8GwEJ31/AAAAFQCG/gOjObsr86vvldUZHCteaJttNQAAAIB5nomvcqOk/TD07DLaWKyG7gAcW5WnfY3WtnvLRAFk09aq1EuiJ6Yba99Zkb+bsxXv89FWjWDg/Z3Psa22JMyi0HEDVsOevy/1sEQ96AGH5ijLzFInfXAM7gaJKXASD7hPbVdjySbgRCdwu0dzmQWHtH+8i1CMVmA2/a5Y/wtlJAAAAIAUZj2US2D378jBwyX1Py7e4sJfea3WSGYZjn4DLlsLGsB88POuh32aOChd1yzF6r6C2sdoPBHQcWBgNGXcx4gF0B5UmyVHg3lIX2NVSG1ZmfuLNJs9iKNu4cHXUmqBbwFYQJBvB69EEtrOw4jSbiTKwHFmqdA/mw1VsMB+khUaVw=="
& alias "usbackup.kitenet.net"
& JoeySites.backupsBackedupFrom hosts "eubackup.kitenet.net" "/home/joey/lib/backup"
& Apt.serviceInstalledRunning "anacron"
& Cron.niceJob "system disk backed up" Cron.Weekly "root" "/"
"rsync -a -x / /home/joey/lib/backup/beaver.kitenet.net/"
--' __|II| ,. --' __|II| ,.
---- __|II|II|__ ( \_,/\ ---- __|II|II|__ ( \_,/\
@ -411,7 +387,7 @@ standardSystemUnhardened hn suite arch motd = host hn
& Sudo.enabledFor "joey" & Sudo.enabledFor "joey"
& GitHome.installedFor "joey" & GitHome.installedFor "joey"
& Apt.installed ["vim", "screen", "less"] & Apt.installed ["vim", "screen", "less"]
& Cron.runPropellor "30 * * * *" & Cron.runPropellor (Cron.Times "30 * * * *")
-- I use postfix, or no MTA. -- I use postfix, or no MTA.
& Apt.removed ["exim4", "exim4-daemon-light", "exim4-config", "exim4-base"] & Apt.removed ["exim4", "exim4-daemon-light", "exim4-config", "exim4-base"]
`onChange` Apt.autoRemove `onChange` Apt.autoRemove
@ -447,15 +423,14 @@ myDnsSecondary = propertyList "dns secondary for all my domains" $ props
branchableSecondary :: RevertableProperty branchableSecondary :: RevertableProperty
branchableSecondary = Dns.secondaryFor ["branchable.com"] hosts "branchable.com" branchableSecondary = Dns.secondaryFor ["branchable.com"] hosts "branchable.com"
-- Currently using diatom (ns2) as primary with secondaries -- Currently using kite (ns4) as primary with secondaries
-- elephant (ns3), kite (ns4) and gandi. -- elephant (ns3) and gandi.
-- kite handles all mail. -- kite handles all mail.
myDnsPrimary :: Bool -> Domain -> [(BindDomain, Record)] -> RevertableProperty myDnsPrimary :: Bool -> Domain -> [(BindDomain, Record)] -> RevertableProperty
myDnsPrimary dnssec domain extras = (if dnssec then Dns.signedPrimary (Weekly Nothing) else Dns.primary) hosts domain myDnsPrimary dnssec domain extras = (if dnssec then Dns.signedPrimary (Weekly Nothing) else Dns.primary) hosts domain
(Dns.mkSOA "ns2.kitenet.net" 100) $ (Dns.mkSOA "ns4.kitenet.net" 100) $
[ (RootDomain, NS $ AbsDomain "ns2.kitenet.net") [ (RootDomain, NS $ AbsDomain "ns4.kitenet.net")
, (RootDomain, NS $ AbsDomain "ns3.kitenet.net") , (RootDomain, NS $ AbsDomain "ns3.kitenet.net")
, (RootDomain, NS $ AbsDomain "ns4.kitenet.net")
, (RootDomain, NS $ AbsDomain "ns6.gandi.net") , (RootDomain, NS $ AbsDomain "ns6.gandi.net")
, (RootDomain, MX 0 $ AbsDomain "kitenet.net") , (RootDomain, MX 0 $ AbsDomain "kitenet.net")
, (RootDomain, TXT "v=spf1 a a:kitenet.net ~all") , (RootDomain, TXT "v=spf1 a a:kitenet.net ~all")
@ -474,13 +449,8 @@ monsters = -- but do want to track their public keys etc.
, host "turtle.kitenet.net" , host "turtle.kitenet.net"
& ipv4 "67.223.19.96" & ipv4 "67.223.19.96"
& ipv6 "2001:4978:f:2d9::2" & ipv6 "2001:4978:f:2d9::2"
& alias "backup.kitenet.net"
& alias "usbackup.kitenet.net"
& Ssh.pubKey SshRsa "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAokMXQiX/NZjA1UbhMdgAscnS5dsmy+Q7bWrQ6tsTZ/o+6N/T5cbjoBHOdpypXJI3y/PiJTDJaQtXIhLa8gFg/EvxMnMz/KG9skADW1361JmfCc4BxicQIO2IOOe6eilPr+YsnOwiHwL0vpUnuty39cppuMWVD25GzxXlS6KQsLCvXLzxLLuNnGC43UAM0q4UwQxDtAZEK1dH2o3HMWhgMP2qEQupc24dbhpO3ecxh2C9678a3oGDuDuNf7mLp3s7ptj5qF3onitpJ82U5o7VajaHoygMaSRFeWxP2c13eM57j3bLdLwxVXFhePcKXARu1iuFTLS5uUf3hN6MkQcOGw=="
, host "mouse.kitenet.net" , host "mouse.kitenet.net"
& ipv6 "2001:4830:1600:492::2" & ipv6 "2001:4830:1600:492::2"
, host "beaver.kitenet.net"
& ipv6 "2001:4830:1600:195::2"
, host "branchable.com" , host "branchable.com"
& ipv4 "66.228.46.55" & ipv4 "66.228.46.55"
& ipv6 "2600:3c03::f03c:91ff:fedf:c0e5" & ipv6 "2600:3c03::f03c:91ff:fedf:c0e5"

13
debian/changelog vendored
View File

@ -1,3 +1,16 @@
propellor (2.1.0) UNRELEASED; urgency=medium
* Additional tor properties, including support for making relays,
and naming bridges, relays, etc.
* New Cron.Times data type, which allows Cron.job to install
daily/monthly/weekly jobs that anacron can run. (API change)
* Fix Git.daemonRunning to restart inetd after enabling the git server.
* Ssh.authorizedKey: Make the authorized_keys file and .ssh directory
be owned by the user, not root.
* Ssh.knownHost: Make the .ssh directory be owned by the user, not root.
-- Joey Hess <id@joeyh.name> Thu, 29 Jan 2015 01:41:07 -0400
propellor (2.0.0) unstable; urgency=medium propellor (2.0.0) unstable; urgency=medium
* Property has been converted to a GADT, and will be Property NoInfo * Property has been converted to a GADT, and will be Property NoInfo

View File

@ -1,5 +1,5 @@
Name: propellor Name: propellor
Version: 2.0.0 Version: 2.1.0
Cabal-Version: >= 1.6 Cabal-Version: >= 1.6
License: BSD3 License: BSD3
Maintainer: Joey Hess <id@joeyh.name> Maintainer: Joey Hess <id@joeyh.name>

View File

@ -1,6 +1,13 @@
{-# LANGUAGE PackageImports #-} {-# LANGUAGE PackageImports #-}
module Propellor.PropAccum where module Propellor.PropAccum
( host
, props
, PropAccum(..)
, (!)
, PropList
, propigateContainer
) where
import Data.Monoid import Data.Monoid
@ -47,9 +54,9 @@ instance PropAccum Host where
data PropList = PropList [Property HasInfo] data PropList = PropList [Property HasInfo]
instance PropAccum PropList where instance PropAccum PropList where
PropList l & p = PropList (l ++ [toProp p]) PropList l & p = PropList (toProp p : l)
PropList l &^ p = PropList ([toProp p] ++ l) PropList l &^ p = PropList (l ++ [toProp p])
getProperties (PropList l) = l getProperties (PropList l) = reverse l
-- | Adds a property in reverted form. -- | Adds a property in reverted form.
(!) :: PropAccum h => h -> RevertableProperty -> h (!) :: PropAccum h => h -> RevertableProperty -> h

View File

@ -70,13 +70,17 @@ reloaded = Service.reloaded "apache2"
-- | Configure apache to use SNI to differentiate between -- | Configure apache to use SNI to differentiate between
-- https hosts. -- https hosts.
--
-- This was off by default in apache 2.2.22. Newver versions enable
-- it by default. This property uses the filename used by the old version.
multiSSL :: Property NoInfo multiSSL :: Property NoInfo
multiSSL = "/etc/apache2/conf.d/ssl" `File.hasContent` multiSSL = check (doesDirectoryExist "/etc/apache2/conf.d") $
[ "NameVirtualHost *:443" "/etc/apache2/conf.d/ssl" `File.hasContent`
, "SSLStrictSNIVHostCheck off" [ "NameVirtualHost *:443"
] , "SSLStrictSNIVHostCheck off"
`describe` "apache SNI enabled" ]
`onChange` reloaded `describe` "apache SNI enabled"
`onChange` reloaded
-- | Config file fragment that can be inserted into a <Directory> -- | Config file fragment that can be inserted into a <Directory>
-- stanza to allow global read access to the directory. -- stanza to allow global read access to the directory.

View File

@ -8,18 +8,26 @@ import Utility.FileMode
import Data.Char import Data.Char
type CronTimes = String -- | When to run a cron job.
--
-- The Daily, Monthly, and Weekly options allow the cron job to be run
-- by anacron, which is useful for non-servers.
data Times
= Times String -- ^ formatted as in crontab(5)
| Daily
| Weekly
| Monthly
-- | Installs a cron job, run as a specified user, in a particular -- | Installs a cron job, that will run as a specified user in a particular
-- directory. Note that the Desc must be unique, as it is used for the -- directory. Note that the Desc must be unique, as it is used for the
-- cron.d/ filename. -- cron job filename.
-- --
-- Only one instance of the cron job is allowed to run at a time, no matter -- Only one instance of the cron job is allowed to run at a time, no matter
-- how long it runs. This is accomplished using flock locking of the cron -- how long it runs. This is accomplished using flock locking of the cron
-- job file. -- job file.
-- --
-- The cron job's output will only be emailed if it exits nonzero. -- The cron job's output will only be emailed if it exits nonzero.
job :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property NoInfo job :: Desc -> Times -> UserName -> FilePath -> String -> Property NoInfo
job desc times user cddir command = combineProperties ("cronned " ++ desc) job desc times user cddir command = combineProperties ("cronned " ++ desc)
[ cronjobfile `File.hasContent` [ cronjobfile `File.hasContent`
[ "# Generated by propellor" [ "# Generated by propellor"
@ -27,8 +35,15 @@ job desc times user cddir command = combineProperties ("cronned " ++ desc)
, "SHELL=/bin/sh" , "SHELL=/bin/sh"
, "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" , "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
, "" , ""
, times ++ "\t" ++ user ++ "\tchronic " ++ shellEscape scriptfile , case times of
Times t -> t ++ "\t" ++ user ++ "\tchronic " ++ shellEscape scriptfile
_ -> case user of
"root" -> "chronic " ++ shellEscape scriptfile
_ -> "chronic su " ++ user ++ " -c " ++ shellEscape scriptfile
] ]
, case times of
Times _ -> doNothing
_ -> cronjobfile `File.mode` combineModes (readModes ++ executeModes)
-- Use a separate script because it makes the cron job name -- Use a separate script because it makes the cron job name
-- prettier in emails, and also allows running the job manually. -- prettier in emails, and also allows running the job manually.
, scriptfile `File.hasContent` , scriptfile `File.hasContent`
@ -44,7 +59,12 @@ job desc times user cddir command = combineProperties ("cronned " ++ desc)
`requires` Apt.installed ["util-linux", "moreutils"] `requires` Apt.installed ["util-linux", "moreutils"]
where where
cmdline = "cd " ++ cddir ++ " && ( " ++ command ++ " )" cmdline = "cd " ++ cddir ++ " && ( " ++ command ++ " )"
cronjobfile = "/etc/cron.d/" ++ name cronjobfile = "/etc" </> cronjobdir </> name
cronjobdir = case times of
Times _ -> "cron.d"
Daily -> "cron.daily"
Weekly -> "cron.weekly"
Monthly -> "cron.monthly"
scriptfile = "/usr/local/bin/" ++ name ++ "_cronjob" scriptfile = "/usr/local/bin/" ++ name ++ "_cronjob"
name = map sanitize desc name = map sanitize desc
sanitize c sanitize c
@ -52,10 +72,10 @@ job desc times user cddir command = combineProperties ("cronned " ++ desc)
| otherwise = '_' | otherwise = '_'
-- | Installs a cron job, and runs it niced and ioniced. -- | Installs a cron job, and runs it niced and ioniced.
niceJob :: Desc -> CronTimes -> UserName -> FilePath -> String -> Property NoInfo niceJob :: Desc -> Times -> UserName -> FilePath -> String -> Property NoInfo
niceJob desc times user cddir command = job desc times user cddir niceJob desc times user cddir command = job desc times user cddir
("nice ionice -c 3 sh -c " ++ shellEscape command) ("nice ionice -c 3 sh -c " ++ shellEscape command)
-- | Installs a cron job to run propellor. -- | Installs a cron job to run propellor.
runPropellor :: CronTimes -> Property NoInfo runPropellor :: Times -> Property NoInfo
runPropellor times = niceJob "propellor" times "root" localdir "./propellor" runPropellor times = niceJob "propellor" times "root" localdir "./propellor"

View File

@ -21,7 +21,7 @@ hasPrivContent :: IsContext c => FilePath -> c -> Property HasInfo
hasPrivContent f = hasPrivContentFrom (PrivDataSourceFile (PrivFile f) f) f hasPrivContent f = hasPrivContentFrom (PrivDataSourceFile (PrivFile f) f) f
-- | Like hasPrivContent, but allows specifying a source -- | Like hasPrivContent, but allows specifying a source
-- for PrivData, rather than using PrivDataSourceFile. -- for PrivData, rather than using PrivDataSourceFile .
hasPrivContentFrom :: (IsContext c, IsPrivDataSource s) => s -> FilePath -> c -> Property HasInfo hasPrivContentFrom :: (IsContext c, IsPrivDataSource s) => s -> FilePath -> c -> Property HasInfo
hasPrivContentFrom = hasPrivContent' writeFileProtected hasPrivContentFrom = hasPrivContent' writeFileProtected

View File

@ -23,7 +23,7 @@ daemonRunning exportdir = setup <!> unsetup
`requires` `requires`
Apt.serviceInstalledRunning "openbsd-inetd" Apt.serviceInstalledRunning "openbsd-inetd"
`onChange` `onChange`
Service.running "openbsd-inetd" Service.reloaded "openbsd-inetd"
`describe` ("git-daemon exporting " ++ exportdir) `describe` ("git-daemon exporting " ++ exportdir)
unsetup = lacksLine conf (mkl "tcp4") unsetup = lacksLine conf (mkl "tcp4")
`requires` `requires`

View File

@ -2,9 +2,18 @@ module Propellor.Property.HostingProvider.Linode where
import Propellor import Propellor
import qualified Propellor.Property.Grub as Grub import qualified Propellor.Property.Grub as Grub
import qualified Propellor.Property.File as File
import Utility.FileMode
-- | Linode's pv-grub-x86_64 does not currently support booting recent -- | Linode's pv-grub-x86_64 does not currently support booting recent
-- Debian kernels compressed with xz. This sets up pv-grub chaing to enable -- Debian kernels compressed with xz. This sets up pv-grub chaing to enable
-- it. -- it.
chainPVGrub :: Grub.TimeoutSecs -> Property NoInfo chainPVGrub :: Grub.TimeoutSecs -> Property NoInfo
chainPVGrub = Grub.chainPVGrub "hd0" "xen/xvda" chainPVGrub = Grub.chainPVGrub "hd0" "xen/xvda"
-- | Linode disables mlocate's cron job's execute permissions,
-- presumably to avoid disk IO. This ensures it's executable.
mlocateEnabled :: Property NoInfo
mlocateEnabled = "/etc/cron.daily/mlocate"
`File.mode` combineModes (readModes ++ executeModes)

View File

@ -36,7 +36,7 @@ data NumClients = OnlyClient | MultipleClients
-- > `requires` Ssh.keyImported SshRsa "root" (Context hostname) -- > `requires` Ssh.keyImported SshRsa "root" (Context hostname)
-- --
-- How awesome is that? -- How awesome is that?
backup :: FilePath -> Cron.CronTimes -> [ObnamParam] -> NumClients -> Property NoInfo backup :: FilePath -> Cron.Times -> [ObnamParam] -> NumClients -> Property NoInfo
backup dir crontimes params numclients = backup dir crontimes params numclients =
backup' dir crontimes params numclients backup' dir crontimes params numclients
`requires` restored dir params `requires` restored dir params
@ -46,7 +46,7 @@ backup dir crontimes params numclients =
-- --
-- The gpg secret key will be automatically imported -- The gpg secret key will be automatically imported
-- into root's keyring using Propellor.Property.Gpg.keyImported -- into root's keyring using Propellor.Property.Gpg.keyImported
backupEncrypted :: FilePath -> Cron.CronTimes -> [ObnamParam] -> NumClients -> Gpg.GpgKeyId -> Property HasInfo backupEncrypted :: FilePath -> Cron.Times -> [ObnamParam] -> NumClients -> Gpg.GpgKeyId -> Property HasInfo
backupEncrypted dir crontimes params numclients keyid = backupEncrypted dir crontimes params numclients keyid =
backup dir crontimes params' numclients backup dir crontimes params' numclients
`requires` Gpg.keyImported keyid "root" `requires` Gpg.keyImported keyid "root"
@ -54,7 +54,7 @@ backupEncrypted dir crontimes params numclients keyid =
params' = ("--encrypt-with=" ++ Gpg.getGpgKeyId keyid) : params params' = ("--encrypt-with=" ++ Gpg.getGpgKeyId keyid) : params
-- | Does a backup, but does not automatically restore. -- | Does a backup, but does not automatically restore.
backup' :: FilePath -> Cron.CronTimes -> [ObnamParam] -> NumClients -> Property NoInfo backup' :: FilePath -> Cron.Times -> [ObnamParam] -> NumClients -> Property NoInfo
backup' dir crontimes params numclients = cronjob `describe` desc backup' dir crontimes params numclients = cronjob `describe` desc
where where
desc = dir ++ " backed up by obnam" desc = dir ++ " backed up by obnam"

View File

@ -4,8 +4,9 @@ module Propellor.Property.Postfix where
import Propellor import Propellor
import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Apt as Apt
import Propellor.Property.File import qualified Propellor.Property.File as File
import qualified Propellor.Property.Service as Service import qualified Propellor.Property.Service as Service
import qualified Propellor.Property.User as User
import qualified Data.Map as M import qualified Data.Map as M
import Data.List import Data.List
@ -103,7 +104,7 @@ mainCfIsSet name = do
-- Note that multiline configurations that continue onto the next line -- Note that multiline configurations that continue onto the next line
-- are not currently supported. -- are not currently supported.
dedupMainCf :: Property NoInfo dedupMainCf :: Property NoInfo
dedupMainCf = fileProperty "postfix main.cf dedupped" dedupCf mainCfFile dedupMainCf = File.fileProperty "postfix main.cf dedupped" dedupCf mainCfFile
dedupCf :: [String] -> [String] dedupCf :: [String] -> [String]
dedupCf ls = dedupCf ls =
@ -125,3 +126,33 @@ dedupCf ls =
dedup c kc ((Right (k, v)):rest) = case M.lookup k kc of dedup c kc ((Right (k, v)):rest) = case M.lookup k kc of
Just n | n > 1 -> dedup c (M.insert k (n - 1) kc) rest Just n | n > 1 -> dedup c (M.insert k (n - 1) kc) rest
_ -> dedup (fmt k v:c) kc rest _ -> dedup (fmt k v:c) kc rest
-- | Installs saslauthd and configures it for postfix, authenticating
-- against PAM.
--
-- Does not configure postfix to use it; eg smtpd_sasl_auth_enable = yes
-- needs to be set to enable use. See
-- https://wiki.debian.org/PostfixAndSASL
saslAuthdInstalled :: Property NoInfo
saslAuthdInstalled = setupdaemon
`requires` Service.running "saslauthd"
`requires` postfixgroup
`requires` dirperm
`requires` Apt.installed ["sasl2-bin"]
`requires` smtpdconf
where
setupdaemon = "/etc/default/saslauthd" `File.containsLines`
[ "START=yes"
, "OPTIONS=\"-c -m " ++ dir ++ "\""
]
`onChange` Service.restarted "saslauthd"
smtpdconf = "/etc/postfix/sasl/smtpd.conf" `File.containsLines`
[ "pwcheck_method: saslauthd"
, "mech_list: PLAIN LOGIN"
]
dirperm = check (not <$> doesDirectoryExist dir) $
cmdProperty "dpkg-statoverride"
[ "--add", "root", "sasl", "710", dir ]
postfixgroup = "postfix" `User.hasGroup` "sasl"
`onChange` restarted
dir = "/var/spool/postfix/var/run/saslauthd"

View File

@ -9,7 +9,7 @@ import qualified Propellor.Property.Cron as Cron
import qualified Propellor.Property.Ssh as Ssh import qualified Propellor.Property.Ssh as Ssh
import qualified Propellor.Property.File as File import qualified Propellor.Property.File as File
import qualified Propellor.Property.Docker as Docker import qualified Propellor.Property.Docker as Docker
import Propellor.Property.Cron (CronTimes) import Propellor.Property.Cron (Times)
builduser :: UserName builduser :: UserName
builduser = "builder" builduser = "builder"
@ -25,7 +25,7 @@ builddir = gitbuilderdir </> "build"
type TimeOut = String -- eg, 5h type TimeOut = String -- eg, 5h
autobuilder :: Architecture -> CronTimes -> TimeOut -> Property HasInfo autobuilder :: Architecture -> Times -> TimeOut -> Property HasInfo
autobuilder arch crontimes timeout = combineProperties "gitannexbuilder" $ props autobuilder arch crontimes timeout = combineProperties "gitannexbuilder" $ props
& Apt.serviceInstalledRunning "cron" & Apt.serviceInstalledRunning "cron"
& Cron.niceJob "gitannexbuilder" crontimes builduser gitbuilderdir & Cron.niceJob "gitannexbuilder" crontimes builduser gitbuilderdir
@ -102,10 +102,10 @@ standardAutoBuilderContainer dockerImage arch buildminute timeout = Docker.conta
& User.accountFor builduser & User.accountFor builduser
& tree arch & tree arch
& buildDepsApt & buildDepsApt
& autobuilder arch (show buildminute ++ " * * * *") timeout & autobuilder arch (Cron.Times $ show buildminute ++ " * * * *") timeout
& Docker.tweaked & Docker.tweaked
androidAutoBuilderContainer :: (System -> Docker.Image) -> Cron.CronTimes -> TimeOut -> Docker.Container androidAutoBuilderContainer :: (System -> Docker.Image) -> Times -> TimeOut -> Docker.Container
androidAutoBuilderContainer dockerImage crontimes timeout = androidAutoBuilderContainer dockerImage crontimes timeout =
androidContainer dockerImage "android-git-annex-builder" (tree "android") builddir androidContainer dockerImage "android-git-annex-builder" (tree "android") builddir
& Apt.unattendedUpgrades & Apt.unattendedUpgrades
@ -166,7 +166,7 @@ armelCompanionContainer dockerImage = Docker.container "armel-git-annex-builder-
& Ssh.authorizedKeys builduser (Context "armel-git-annex-builder") & Ssh.authorizedKeys builduser (Context "armel-git-annex-builder")
& Docker.tweaked & Docker.tweaked
armelAutoBuilderContainer :: (System -> Docker.Image) -> Cron.CronTimes -> TimeOut -> Docker.Container armelAutoBuilderContainer :: (System -> Docker.Image) -> Times -> TimeOut -> Docker.Container
armelAutoBuilderContainer dockerImage crontimes timeout = Docker.container "armel-git-annex-builder" armelAutoBuilderContainer dockerImage crontimes timeout = Docker.container "armel-git-annex-builder"
(dockerImage $ System (Debian Unstable) "armel") (dockerImage $ System (Debian Unstable) "armel")
& os (System (Debian Testing) "armel") & os (System (Debian Testing) "armel")

View File

@ -24,6 +24,7 @@ import Data.String.Utils
oldUseNetServer :: [Host] -> Property HasInfo oldUseNetServer :: [Host] -> Property HasInfo
oldUseNetServer hosts = propertyList "olduse.net server" $ props oldUseNetServer hosts = propertyList "olduse.net server" $ props
& Apt.installed ["leafnode"]
& oldUseNetInstalled "oldusenet-server" & oldUseNetInstalled "oldusenet-server"
& Obnam.latestVersion & Obnam.latestVersion
& oldUseNetBackup & oldUseNetBackup
@ -32,7 +33,6 @@ oldUseNetServer hosts = propertyList "olduse.net server" $ props
removeDirectoryRecursive newsspool removeDirectoryRecursive newsspool
createSymbolicLink (datadir </> "news") newsspool createSymbolicLink (datadir </> "news") newsspool
) )
& Apt.installed ["leafnode"]
& "/etc/news/leafnode/config" `File.hasContent` & "/etc/news/leafnode/config" `File.hasContent`
[ "# olduse.net configuration (deployed by propellor)" [ "# olduse.net configuration (deployed by propellor)"
, "expire = 1000000" -- no expiry via texpire , "expire = 1000000" -- no expiry via texpire
@ -45,8 +45,8 @@ oldUseNetServer hosts = propertyList "olduse.net server" $ props
& Apt.serviceInstalledRunning "openbsd-inetd" & Apt.serviceInstalledRunning "openbsd-inetd"
& File.notPresent "/etc/cron.daily/leafnode" & File.notPresent "/etc/cron.daily/leafnode"
& File.notPresent "/etc/cron.d/leafnode" & File.notPresent "/etc/cron.d/leafnode"
& Cron.niceJob "oldusenet-expire" "11 1 * * *" "news" newsspool expirecommand & Cron.niceJob "oldusenet-expire" (Cron.Times "11 1 * * *") "news" newsspool expirecommand
& Cron.niceJob "oldusenet-uucp" "*/5 * * * *" "news" "/" uucpcommand & Cron.niceJob "oldusenet-uucp" (Cron.Times "*/5 * * * *") "news" "/" uucpcommand
& Apache.siteEnabled "nntp.olduse.net" nntpcfg & Apache.siteEnabled "nntp.olduse.net" nntpcfg
where where
newsspool = "/var/spool/news" newsspool = "/var/spool/news"
@ -65,12 +65,14 @@ oldUseNetServer hosts = propertyList "olduse.net server" $ props
, " </Directory>" , " </Directory>"
] ]
oldUseNetBackup = Obnam.backup datadir "33 4 * * *" oldUseNetBackup = Obnam.backup datadir (Cron.Times "33 4 * * *")
[ "--repository=sftp://2318@usw-s002.rsync.net/~/olduse.net" [ "--repository=sftp://2318@usw-s002.rsync.net/~/olduse.net"
, "--client-name=spool" , "--client-name=spool"
, "--ssh-key=" ++ keyfile
] Obnam.OnlyClient ] Obnam.OnlyClient
`requires` Ssh.keyImported SshRsa "root" (Context "olduse.net") `requires` Ssh.keyImported' (Just keyfile) SshRsa "root" (Context "olduse.net")
`requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root"
keyfile = "/root/.ssh/olduse.net.key"
oldUseNetShellBox :: Property HasInfo oldUseNetShellBox :: Property HasInfo
oldUseNetShellBox = propertyList "olduse.net shellbox" $ props oldUseNetShellBox = propertyList "olduse.net shellbox" $ props
@ -113,12 +115,12 @@ mumbleServer :: [Host] -> Property HasInfo
mumbleServer hosts = combineProperties hn $ props mumbleServer hosts = combineProperties hn $ props
& Apt.serviceInstalledRunning "mumble-server" & Apt.serviceInstalledRunning "mumble-server"
& Obnam.latestVersion & Obnam.latestVersion
& Obnam.backup "/var/lib/mumble-server" "55 5 * * *" & Obnam.backup "/var/lib/mumble-server" (Cron.Times "55 5 * * *")
[ "--repository=sftp://joey@usbackup.kitenet.net/~/lib/backup/" ++ hn ++ ".obnam" [ "--repository=sftp://2318@usw-s002.rsync.net/~/" ++ hn ++ ".obnam"
, "--client-name=mumble" , "--client-name=mumble"
] Obnam.OnlyClient ] Obnam.OnlyClient
`requires` Ssh.keyImported SshRsa "root" (Context hn) `requires` Ssh.keyImported SshRsa "root" (Context hn)
`requires` Ssh.knownHost hosts "usbackup.kitenet.net" "root" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root"
& trivial (cmdProperty "chown" ["-R", "mumble-server:mumble-server", "/var/lib/mumble-server"]) & trivial (cmdProperty "chown" ["-R", "mumble-server:mumble-server", "/var/lib/mumble-server"])
where where
hn = "mumble.debian.net" hn = "mumble.debian.net"
@ -129,8 +131,8 @@ obnamLowMem = combineProperties "obnam tuned for low memory use"
, "/etc/obnam.conf" `File.containsLines` , "/etc/obnam.conf" `File.containsLines`
[ "[config]" [ "[config]"
, "# Suggested by liw to keep Obnam memory consumption down (at some speed cost)." , "# Suggested by liw to keep Obnam memory consumption down (at some speed cost)."
, "upload-queue-size = 128" , "upload-queue-size = 96"
, "lru-size = 128" , "lru-size = 96"
] ]
] ]
@ -138,20 +140,20 @@ obnamLowMem = combineProperties "obnam tuned for low memory use"
gitServer :: [Host] -> Property HasInfo gitServer :: [Host] -> Property HasInfo
gitServer hosts = propertyList "git.kitenet.net setup" $ props gitServer hosts = propertyList "git.kitenet.net setup" $ props
& Obnam.latestVersion & Obnam.latestVersion
& Obnam.backupEncrypted "/srv/git" "33 3 * * *" & Obnam.backupEncrypted "/srv/git" (Cron.Times "33 3 * * *")
[ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net" [ "--repository=sftp://2318@usw-s002.rsync.net/~/git.kitenet.net"
, "--ssh-key=" ++ sshkey
, "--client-name=wren" -- historical , "--client-name=wren" -- historical
] Obnam.OnlyClient (Gpg.GpgKeyId "1B169BE1") ] Obnam.OnlyClient (Gpg.GpgKeyId "1B169BE1")
`requires` Ssh.keyImported SshRsa "root" (Context "git.kitenet.net") `requires` Ssh.keyImported' (Just sshkey) SshRsa "root" (Context "git.kitenet.net")
`requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "root"
`requires` Ssh.authorizedKeys "family" (Context "git.kitenet.net") `requires` Ssh.authorizedKeys "family" (Context "git.kitenet.net")
`requires` User.accountFor "family" `requires` User.accountFor "family"
& Apt.installed ["git", "rsync", "gitweb"] & Apt.installed ["git", "rsync", "gitweb"]
-- backport avoids channel flooding on branch merge & Apt.installed ["git-annex"]
& Apt.installedBackport ["kgb-client"] & Apt.installed ["kgb-client"]
-- backport supports ssh event notification
& Apt.installedBackport ["git-annex"]
& File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" anyContext & File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" anyContext
`requires` File.dirExists "/etc/kgb-bot/"
& Git.daemonRunning "/srv/git" & Git.daemonRunning "/srv/git"
& "/etc/gitweb.conf" `File.containsLines` & "/etc/gitweb.conf" `File.containsLines`
[ "$projectroot = '/srv/git';" [ "$projectroot = '/srv/git';"
@ -168,6 +170,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" $ props
& website "git.joeyh.name" & website "git.joeyh.name"
& Apache.modEnabled "cgi" & Apache.modEnabled "cgi"
where where
sshkey = "/root/.ssh/git.kitenet.net.key"
website hn = apacheSite hn True website hn = apacheSite hn True
[ " DocumentRoot /srv/web/git.kitenet.net/" [ " DocumentRoot /srv/web/git.kitenet.net/"
, " <Directory /srv/web/git.kitenet.net/>" , " <Directory /srv/web/git.kitenet.net/>"
@ -175,6 +178,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" $ props
, " AllowOverride None" , " AllowOverride None"
, " AddHandler cgi-script .cgi" , " AddHandler cgi-script .cgi"
, " DirectoryIndex index.cgi" , " DirectoryIndex index.cgi"
, Apache.allowAll
, " </Directory>" , " </Directory>"
, "" , ""
, " ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/" , " ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/"
@ -204,7 +208,7 @@ annexWebSite origin hn uuid remotes = propertyList (hn ++" website using git-ann
setup = userScriptProperty "joey" setupscript setup = userScriptProperty "joey" setupscript
setupscript = setupscript =
[ "cd " ++ shellEscape dir [ "cd " ++ shellEscape dir
, "git config annex.uuid " ++ shellEscape uuid , "git annex reinit " ++ shellEscape uuid
] ++ map addremote remotes ++ ] ++ map addremote remotes ++
[ "git annex get" [ "git annex get"
, "git update-server-info" , "git update-server-info"
@ -217,14 +221,14 @@ annexWebSite origin hn uuid remotes = propertyList (hn ++" website using git-ann
, " <Directory /srv/web/"++hn++">" , " <Directory /srv/web/"++hn++">"
, " Options FollowSymLinks" , " Options FollowSymLinks"
, " AllowOverride None" , " AllowOverride None"
, Apache.allowAll
, " </Directory>" , " </Directory>"
, " <Directory /srv/web/"++hn++">" , " <Directory /srv/web/"++hn++">"
, " Options Indexes FollowSymLinks ExecCGI" , " Options Indexes FollowSymLinks ExecCGI"
, " AllowOverride None" , " AllowOverride None"
, " AddHandler cgi-script .cgi" , " AddHandler cgi-script .cgi"
, " DirectoryIndex index.html index.cgi" , " DirectoryIndex index.html index.cgi"
, " Order allow,deny" , Apache.allowAll
, " allow from all"
, " </Directory>" , " </Directory>"
] ]
@ -252,8 +256,7 @@ apachecfg hn withssl middle
, " <Directory \"/usr/share/apache2/icons\">" , " <Directory \"/usr/share/apache2/icons\">"
, " Options Indexes MultiViews" , " Options Indexes MultiViews"
, " AllowOverride None" , " AllowOverride None"
, " Order allow,deny" , Apache.allowAll
, " Allow from all"
, " </Directory>" , " </Directory>"
, "</VirtualHost>" , "</VirtualHost>"
] ]
@ -288,6 +291,22 @@ gitAnnexDistributor = combineProperties "git-annex distributor, including rsync
, File.ownerGroup d "joey" "joey" , File.ownerGroup d "joey" "joey"
] ]
downloads :: [Host] -> Property HasInfo
downloads hosts = annexWebSite "/srv/git/downloads.git"
"downloads.kitenet.net"
"840760dc-08f0-11e2-8c61-576b7e66acfd"
[("eubackup", "ssh://eubackup.kitenet.net/~/lib/downloads/")]
`requires` Ssh.knownHost hosts "eubackup.kitenet.net" "joey"
tmp :: Property HasInfo
tmp = propertyList "tmp.kitenet.net" $ props
& annexWebSite "/srv/git/joey/tmp.git"
"tmp.kitenet.net"
"26fd6e38-1226-11e2-a75f-ff007033bdba"
[]
& twitRss
& pumpRss
-- Twitter, you kill us. -- Twitter, you kill us.
twitRss :: Property HasInfo twitRss :: Property HasInfo
twitRss = combineProperties "twitter rss" $ props twitRss = combineProperties "twitter rss" $ props
@ -297,7 +316,7 @@ twitRss = combineProperties "twitter rss" $ props
& feed "http://twitter.com/search/realtime?q=olduse+OR+git-annex+OR+debhelper+OR+etckeeper+OR+ikiwiki+-ashley_ikiwiki" "twittergrep" & feed "http://twitter.com/search/realtime?q=olduse+OR+git-annex+OR+debhelper+OR+etckeeper+OR+ikiwiki+-ashley_ikiwiki" "twittergrep"
where where
dir = "/srv/web/tmp.kitenet.net/twitrss" dir = "/srv/web/tmp.kitenet.net/twitrss"
crontime = "15 * * * *" crontime = Cron.Times "15 * * * *"
feed url desc = Cron.job desc crontime "joey" dir $ feed url desc = Cron.job desc crontime "joey" dir $
"./twitRss " ++ shellEscape url ++ " > " ++ shellEscape ("../" ++ desc ++ ".rss") "./twitRss " ++ shellEscape url ++ " > " ++ shellEscape ("../" ++ desc ++ ".rss")
compiled = userScriptProperty "joey" compiled = userScriptProperty "joey"
@ -311,9 +330,8 @@ twitRss = combineProperties "twitter rss" $ props
] ]
-- Work around for expired ssl cert. -- Work around for expired ssl cert.
-- (no longer expired, TODO remove this and change urls)
pumpRss :: Property NoInfo pumpRss :: Property NoInfo
pumpRss = Cron.job "pump rss" "15 * * * *" "joey" "/srv/web/tmp.kitenet.net/" pumpRss = Cron.job "pump rss" (Cron.Times "15 * * * *") "joey" "/srv/web/tmp.kitenet.net/"
"wget https://pump2rss.com/feed/joeyh@identi.ca.atom -O pump.atom --no-check-certificate 2>/dev/null" "wget https://pump2rss.com/feed/joeyh@identi.ca.atom -O pump.atom --no-check-certificate 2>/dev/null"
ircBouncer :: Property HasInfo ircBouncer :: Property HasInfo
@ -323,7 +341,7 @@ ircBouncer = propertyList "IRC bouncer" $ props
& File.dirExists (takeDirectory conf) & File.dirExists (takeDirectory conf)
& File.hasPrivContent conf anyContext & File.hasPrivContent conf anyContext
& File.ownerGroup conf "znc" "znc" & File.ownerGroup conf "znc" "znc"
& Cron.job "znconboot" "@reboot" "znc" "~" "znc" & Cron.job "znconboot" (Cron.Times "@reboot") "znc" "~" "znc"
-- ensure running if it was not already -- ensure running if it was not already
& trivial (userScriptProperty "znc" ["znc || true"]) & trivial (userScriptProperty "znc" ["znc || true"])
`describe` "znc running" `describe` "znc running"
@ -347,9 +365,9 @@ githubBackup :: Property HasInfo
githubBackup = propertyList "github-backup box" $ props githubBackup = propertyList "github-backup box" $ props
& Apt.installed ["github-backup", "moreutils"] & Apt.installed ["github-backup", "moreutils"]
& githubKeys & githubKeys
& Cron.niceJob "github-backup run" "30 4 * * *" "joey" & Cron.niceJob "github-backup run" (Cron.Times "30 4 * * *") "joey"
"/home/joey/lib/backup" backupcmd "/home/joey/lib/backup" backupcmd
& Cron.niceJob "gitriddance" "30 4 * * *" "joey" & Cron.niceJob "gitriddance" (Cron.Times "30 4 * * *") "joey"
"/home/joey/lib/backup" gitriddancecmd "/home/joey/lib/backup" gitriddancecmd
where where
backupcmd = intercalate "&&" $ backupcmd = intercalate "&&" $
@ -385,17 +403,17 @@ githubMirrors =
plzuseurl u = "please submit changes to " ++ u ++ " instead of using github pull requests" plzuseurl u = "please submit changes to " ++ u ++ " instead of using github pull requests"
rsyncNetBackup :: [Host] -> Property NoInfo rsyncNetBackup :: [Host] -> Property NoInfo
rsyncNetBackup hosts = Cron.niceJob "rsync.net copied in daily" "30 5 * * *" rsyncNetBackup hosts = Cron.niceJob "rsync.net copied in daily" (Cron.Times "30 5 * * *")
"joey" "/home/joey/lib/backup" "mkdir -p rsync.net && rsync --delete -az 2318@usw-s002.rsync.net: rsync.net" "joey" "/home/joey/lib/backup" "mkdir -p rsync.net && rsync --delete -az 2318@usw-s002.rsync.net: rsync.net"
`requires` Ssh.knownHost hosts "usw-s002.rsync.net" "joey" `requires` Ssh.knownHost hosts "usw-s002.rsync.net" "joey"
backupsBackedupTo :: [Host] -> HostName -> FilePath -> Property NoInfo backupsBackedupFrom :: [Host] -> HostName -> FilePath -> Property NoInfo
backupsBackedupTo hosts desthost destdir = Cron.niceJob desc backupsBackedupFrom hosts srchost destdir = Cron.niceJob desc
"1 1 * * 3" "joey" "/" cmd (Cron.Times "@reboot") "joey" "/" cmd
`requires` Ssh.knownHost hosts desthost "joey" `requires` Ssh.knownHost hosts srchost "joey"
where where
desc = "backups copied to " ++ desthost ++ " weekly" desc = "backups copied from " ++ srchost ++ " on boot"
cmd = "rsync -az --delete /home/joey/lib/backup " ++ desthost ++ ":" ++ destdir cmd = "rsync -az --bwlimit=300K --partial --delete " ++ srchost ++ ":lib/backup/ " ++ destdir </> srchost
obnamRepos :: [String] -> Property NoInfo obnamRepos :: [String] -> Property NoInfo
obnamRepos rs = propertyList ("obnam repos for " ++ unwords rs) obnamRepos rs = propertyList ("obnam repos for " ++ unwords rs)
@ -408,7 +426,7 @@ obnamRepos rs = propertyList ("obnam repos for " ++ unwords rs)
`before` File.ownerGroup d "joey" "joey" `before` File.ownerGroup d "joey" "joey"
podcatcher :: Property NoInfo podcatcher :: Property NoInfo
podcatcher = Cron.niceJob "podcatcher run hourly" "55 * * * *" podcatcher = Cron.niceJob "podcatcher run hourly" (Cron.Times "55 * * * *")
"joey" "/home/joey/lib/sound/podcasts" "joey" "/home/joey/lib/sound/podcasts"
"xargs git-annex importfeed -c annex.genmetadata=true < feeds; mr --quiet update" "xargs git-annex importfeed -c annex.genmetadata=true < feeds; mr --quiet update"
`requires` Apt.installed ["git-annex", "myrepos"] `requires` Apt.installed ["git-annex", "myrepos"]
@ -450,6 +468,8 @@ kiteMailServer = propertyList "kitenet.net mail server" $ props
& dkimInstalled & dkimInstalled
& Postfix.saslAuthdInstalled
& Apt.installed ["maildrop"] & Apt.installed ["maildrop"]
& "/etc/maildroprc" `File.hasContent` & "/etc/maildroprc" `File.hasContent`
[ "# Global maildrop filter file (deployed with propellor)" [ "# Global maildrop filter file (deployed with propellor)"
@ -514,8 +534,13 @@ kiteMailServer = propertyList "kitenet.net mail server" $ props
, "# Filter out client relay lines from headers." , "# Filter out client relay lines from headers."
, "header_checks = pcre:$config_directory/obscure_client_relay.pcre" , "header_checks = pcre:$config_directory/obscure_client_relay.pcre"
, "# Password auth for relaying (used by errol)"
, "smtpd_sasl_auth_enable = yes"
, "smtpd_sasl_security_options = noanonymous"
, "smtpd_sasl_local_domain = kitenet.net"
, "# Enable postgrey." , "# Enable postgrey."
, "smtpd_recipient_restrictions = permit_tls_clientcerts,permit_mynetworks,reject_unauth_destination,check_policy_service inet:127.0.0.1:10023" , "smtpd_recipient_restrictions = permit_tls_clientcerts,permit_sasl_authenticated,,permit_mynetworks,reject_unauth_destination,check_policy_service inet:127.0.0.1:10023"
, "# Enable spamass-milter, amavis-milter, opendkim" , "# Enable spamass-milter, amavis-milter, opendkim"
, "smtpd_milters = unix:/spamass/spamass.sock unix:amavis/amavis.sock inet:localhost:8891" , "smtpd_milters = unix:/spamass/spamass.sock unix:amavis/amavis.sock inet:localhost:8891"

View File

@ -12,6 +12,7 @@ module Propellor.Property.Ssh (
pubKey, pubKey,
getPubKey, getPubKey,
keyImported, keyImported,
keyImported',
knownHost, knownHost,
authorizedKeys, authorizedKeys,
listenPort listenPort
@ -147,13 +148,25 @@ getPubKey = asks (_sshPubKey . hostInfo)
-- | Sets up a user with a ssh private key and public key pair from the -- | Sets up a user with a ssh private key and public key pair from the
-- PrivData. -- PrivData.
--
-- If the user already has a private/public key, it is left unchanged.
keyImported :: IsContext c => SshKeyType -> UserName -> c -> Property HasInfo keyImported :: IsContext c => SshKeyType -> UserName -> c -> Property HasInfo
keyImported keytype user context = combineProperties desc keyImported = keyImported' Nothing
-- | A file can be speficied to write the key to somewhere other than
-- usual. Allows a user to have multiple keys for different roles.
keyImported' :: IsContext c => Maybe FilePath -> SshKeyType -> UserName -> c -> Property HasInfo
keyImported' dest keytype user context = combineProperties desc
[ installkey (SshPubKey keytype user) (install writeFile ".pub") [ installkey (SshPubKey keytype user) (install writeFile ".pub")
, installkey (SshPrivKey keytype user) (install writeFileProtected "") , installkey (SshPrivKey keytype user) (install writeFileProtected "")
] ]
where where
desc = user ++ " has ssh key (" ++ fromKeyType keytype ++ ")" desc = unwords $ catMaybes
[ Just user
, Just "has ssh key"
, dest
, Just $ "(" ++ fromKeyType keytype ++ ")"
]
installkey p a = withPrivData p context $ \getkey -> installkey p a = withPrivData p context $ \getkey ->
property desc $ getkey a property desc $ getkey a
install writer ext key = do install writer ext key = do
@ -168,9 +181,11 @@ keyImported keytype user context = combineProperties desc
, File.ownerGroup (takeDirectory f) user user , File.ownerGroup (takeDirectory f) user user
] ]
) )
keyfile ext = do keyfile ext = case dest of
home <- homeDirectory <$> getUserEntryForName user Nothing -> do
return $ home </> ".ssh" </> "id_" ++ fromKeyType keytype ++ ext home <- homeDirectory <$> getUserEntryForName user
return $ home </> ".ssh" </> "id_" ++ fromKeyType keytype ++ ext
Just f -> return $ f ++ ext
fromKeyType :: SshKeyType -> String fromKeyType :: SshKeyType -> String
fromKeyType SshRsa = "rsa" fromKeyType SshRsa = "rsa"
@ -178,7 +193,7 @@ fromKeyType SshDsa = "dsa"
fromKeyType SshEcdsa = "ecdsa" fromKeyType SshEcdsa = "ecdsa"
fromKeyType SshEd25519 = "ed25519" fromKeyType SshEd25519 = "ed25519"
-- | Puts some host's ssh public key(s), as set using 'pubKey', -- | Puts some host's ssh public key(s), as set using 'pubKey' or 'hostKey'
-- into the known_hosts file for a user. -- into the known_hosts file for a user.
knownHost :: [Host] -> HostName -> UserName -> Property NoInfo knownHost :: [Host] -> HostName -> UserName -> Property NoInfo
knownHost hosts hn user = property desc $ knownHost hosts hn user = property desc $
@ -192,6 +207,7 @@ knownHost hosts hn user = property desc $
, f `File.containsLines` , f `File.containsLines`
(map (\k -> hn ++ " " ++ k) (M.elems m)) (map (\k -> hn ++ " " ++ k) (M.elems m))
, File.ownerGroup f user user , File.ownerGroup f user user
, File.ownerGroup (takeDirectory f) user user
] ]
go _ = do go _ = do
warningMessage $ "no configred pubKey for " ++ hn warningMessage $ "no configred pubKey for " ++ hn
@ -215,12 +231,17 @@ authorizedKeys user context = withPrivData (SshAuthorizedKeys user) context $ \g
-- | Ensures that a user's authorized_keys contains a line. -- | Ensures that a user's authorized_keys contains a line.
-- Any other lines in the file are preserved as-is. -- Any other lines in the file are preserved as-is.
authorizedKey :: UserName -> String -> Property NoInfo authorizedKey :: UserName -> String -> Property NoInfo
authorizedKey user l = property (user ++ " has autorized_keys line " ++ l) $ do authorizedKey user l = property desc $ do
f <- liftIO $ dotFile "authorized_keys" user f <- liftIO $ dotFile "authorized_keys" user
ensureProperty $ ensureProperty $ combineProperties desc
f `File.containsLine` l [ f `File.containsLine` l
`requires` File.dirExists (takeDirectory f) `requires` File.dirExists (takeDirectory f)
`onChange` File.mode f (combineModes [ownerWriteMode, ownerReadMode]) `onChange` File.mode f (combineModes [ownerWriteMode, ownerReadMode])
, File.ownerGroup f user user
, File.ownerGroup (takeDirectory f) user user
]
where
desc = user ++ " has autorized_keys line " ++ l
-- | Makes the ssh server listen on a given port, in addition to any other -- | Makes the ssh server listen on a given port, in addition to any other
-- ports it is configured to listen on. -- ports it is configured to listen on.

View File

@ -7,19 +7,78 @@ import qualified Propellor.Property.Service as Service
import Utility.FileMode import Utility.FileMode
import System.Posix.Files import System.Posix.Files
import Data.Char
type HiddenServiceName = String type HiddenServiceName = String
type NodeName = String
-- | Sets up a tor bridge. (Not a relay or exit node.)
--
-- Uses port 443
isBridge :: Property NoInfo isBridge :: Property NoInfo
isBridge = setup `requires` Apt.installed ["tor"] isBridge = isBridge' []
isBridge' :: [String] -> Property NoInfo
isBridge' extraconfig = server config
`describe` "tor bridge" `describe` "tor bridge"
where where
setup = mainConfig `File.hasContent` config =
[ "SocksPort 0" [ "BridgeRelay 1"
, "ORPort 443"
, "BridgeRelay 1"
, "Exitpolicy reject *:*" , "Exitpolicy reject *:*"
] `onChange` restarted , "ORPort 443"
] ++ extraconfig
-- | Sets up a tor relay.
--
-- Uses port 443
isRelay :: Property NoInfo
isRelay = isRelay' []
isRelay' :: [String] -> Property NoInfo
isRelay' extraconfig = server config
`describe` "tor relay"
where
config =
[ "BridgeRelay 0"
, "Exitpolicy reject *:*"
, "ORPort 443"
] ++ extraconfig
-- | Converts a property like isBridge' or isRelay' to be a named
-- node, with a known private key.
--
-- This can be moved to a different IP without needing to wait to
-- accumulate trust.
--
-- The base property can be used to start out and then upgraded to
-- a named property later.
named :: NodeName -> ([String] -> Property NoInfo) -> Property HasInfo
named n basep = p `describe` (getDesc p ++ " " ++ n)
where
p = basep ["Nickname " ++ saneNickname n]
`requires` torPrivKey (Context ("tor " ++ n))
-- | A tor server (bridge, relay, or exit)
-- Don't use if you just want to run tor for personal use.
server :: [String] -> Property NoInfo
server extraconfig = setup
`requires` Apt.installed ["tor", "ntp"]
`describe` "tor server"
where
setup = mainConfig `File.hasContent` config
`onChange` restarted
config =
[ "SocksPort 0"
] ++ extraconfig
torPrivKey :: Context -> Property HasInfo
torPrivKey context = f `File.hasPrivContent` context
`onChange` File.ownerGroup f user user
-- install tor first, so the directory exists with right perms
`requires` Apt.installed ["tor"]
where
f = "/var/lib/tor/keys/secret_id_key"
hiddenServiceAvailable :: HiddenServiceName -> Int -> Property NoInfo hiddenServiceAvailable :: HiddenServiceName -> Int -> Property NoInfo
hiddenServiceAvailable hn port = hiddenServiceHostName prop hiddenServiceAvailable hn port = hiddenServiceHostName prop
@ -80,3 +139,14 @@ varRun = "/var/run/tor"
user :: UserName user :: UserName
user = "debian-tor" user = "debian-tor"
type NickName = String
-- | Convert String to a valid tor NickName.
saneNickname :: String -> NickName
saneNickname s
| null n = "unnamed"
| otherwise = n
where
legal c = isNumber c || isAsciiUpper c || isAsciiLower c
n = take 19 $ filter legal s