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.Docker as Docker
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.Grub as Grub
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.Journald as Journald
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.Linode as Linode
import qualified Propellor.Property.SiteSpecific.GitHome as GitHome
@ -47,6 +45,7 @@ hosts = -- (o) `
, kite
, diatom
, elephant
, beaver
] ++ monsters
testvm :: Host
@ -86,7 +85,7 @@ clam = standardSystem "clam.kitenet.net" Unstable "amd64"
& Ssh.randomHostKeys
& Apt.unattendedUpgrades
& Network.ipv6to4
& Tor.isBridge
& Tor.named "kite1" Tor.isRelay'
& Postfix.satellite
& 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 "i386" 45 "2h")
& Docker.docked (GitAnnexBuilder.armelCompanionContainer dockerImage)
& Docker.docked (GitAnnexBuilder.armelAutoBuilderContainer dockerImage "1 3 * * *" "5h")
& Docker.docked (GitAnnexBuilder.androidAutoBuilderContainer dockerImage "1 1 * * *" "3h")
& Docker.docked (GitAnnexBuilder.armelAutoBuilderContainer dockerImage (Cron.Times "1 3 * * *") "5h")
& Docker.docked (GitAnnexBuilder.androidAutoBuilderContainer dockerImage (Cron.Times "1 1 * * *") "3h")
& Docker.garbageCollected `period` Daily
& Apt.buildDep ["git-annex"] `period` Daily
@ -128,7 +127,7 @@ orca = standardSystem "orca.kitenet.net" Unstable "amd64"
-- with propellor.
kite :: Host
kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
[ "Welcome to the new kitenet.net server!" ]
[ "Welcome to kite!" ]
& ipv4 "66.228.36.95"
& ipv6 "2600:3c03::f03c:91ff:fe73:b0d2"
& alias "kitenet.net"
@ -143,6 +142,7 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& Network.static "eth0" `requires` Network.cleanInterfacesFile
& Apt.installed ["linux-image-amd64"]
& Linode.chainPVGrub 5
& Linode.mlocateEnabled
& Apt.unattendedUpgrades
& Systemd.installed
& Systemd.persistentJournal
@ -150,7 +150,7 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& Ssh.passwordAuthentication True
-- Since ssh password authentication is allowed:
& Apt.serviceInstalledRunning "fail2ban"
& Obnam.backupEncrypted "/" "33 1 * * *"
& Obnam.backupEncrypted "/" (Cron.Times "33 1 * * *")
[ "--repository=sftp://joey@eubackup.kitenet.net/~/lib/backup/kite.obnam"
, "--client-name=kitenet.net"
, "--exclude=/var/cache"
@ -171,12 +171,18 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& alias "mail.kitenet.net"
& JoeySites.kiteMailServer
& alias "ns4.kitenet.net"
& myDnsSecondary
& alias "ns4.branchable.com"
& branchableSecondary
& JoeySites.kitenetHttps
& 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"
& Apt.serviceInstalledRunning "bitlbee"
@ -201,73 +207,32 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
& Docker.configured
& Docker.garbageCollected `period` Daily
& 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"
! Docker.docked oldusenetShellBox
& 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 "resources.olduse.net"
& JoeySites.oldUseNetServer hosts
& alias "ns2.kitenet.net"
& alias "ns4.kitenet.net"
& myDnsPrimary True "kitenet.net" []
& myDnsPrimary True "joeyh.name" []
& myDnsPrimary True "ikiwiki.info" []
& myDnsPrimary True "olduse.net"
[ (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk")
]
& alias "ns3.branchable.com"
& alias "ns4.branchable.com"
& branchableSecondary
& 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 = standardSystem "elephant.kitenet.net" Unstable "amd64"
[ "Storage, big data, and backups, omnomnom!"
@ -294,7 +259,6 @@ elephant = standardSystem "elephant.kitenet.net" Unstable "amd64"
& JoeySites.obnamRepos ["wren", "pell", "kite"]
& JoeySites.githubBackup
& JoeySites.rsyncNetBackup hosts
& JoeySites.backupsBackedupTo hosts "usbackup.kitenet.net" "lib/backup/eubackup"
& alias "podcatcher.kitenet.net"
& JoeySites.podcatcher
@ -328,6 +292,18 @@ elephant = standardSystem "elephant.kitenet.net" Unstable "amd64"
-- block 22.
& 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|__ ( \_,/\
@ -411,7 +387,7 @@ standardSystemUnhardened hn suite arch motd = host hn
& Sudo.enabledFor "joey"
& GitHome.installedFor "joey"
& Apt.installed ["vim", "screen", "less"]
& Cron.runPropellor "30 * * * *"
& Cron.runPropellor (Cron.Times "30 * * * *")
-- I use postfix, or no MTA.
& Apt.removed ["exim4", "exim4-daemon-light", "exim4-config", "exim4-base"]
`onChange` Apt.autoRemove
@ -447,15 +423,14 @@ myDnsSecondary = propertyList "dns secondary for all my domains" $ props
branchableSecondary :: RevertableProperty
branchableSecondary = Dns.secondaryFor ["branchable.com"] hosts "branchable.com"
-- Currently using diatom (ns2) as primary with secondaries
-- elephant (ns3), kite (ns4) and gandi.
-- Currently using kite (ns4) as primary with secondaries
-- elephant (ns3) and gandi.
-- kite handles all mail.
myDnsPrimary :: Bool -> Domain -> [(BindDomain, Record)] -> RevertableProperty
myDnsPrimary dnssec domain extras = (if dnssec then Dns.signedPrimary (Weekly Nothing) else Dns.primary) hosts domain
(Dns.mkSOA "ns2.kitenet.net" 100) $
[ (RootDomain, NS $ AbsDomain "ns2.kitenet.net")
(Dns.mkSOA "ns4.kitenet.net" 100) $
[ (RootDomain, NS $ AbsDomain "ns4.kitenet.net")
, (RootDomain, NS $ AbsDomain "ns3.kitenet.net")
, (RootDomain, NS $ AbsDomain "ns4.kitenet.net")
, (RootDomain, NS $ AbsDomain "ns6.gandi.net")
, (RootDomain, MX 0 $ AbsDomain "kitenet.net")
, (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"
& ipv4 "67.223.19.96"
& 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"
& ipv6 "2001:4830:1600:492::2"
, host "beaver.kitenet.net"
& ipv6 "2001:4830:1600:195::2"
, host "branchable.com"
& ipv4 "66.228.46.55"
& 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
* Property has been converted to a GADT, and will be Property NoInfo

View File

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

View File

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

View File

@ -70,13 +70,17 @@ reloaded = Service.reloaded "apache2"
-- | Configure apache to use SNI to differentiate between
-- 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 = "/etc/apache2/conf.d/ssl" `File.hasContent`
[ "NameVirtualHost *:443"
, "SSLStrictSNIVHostCheck off"
]
`describe` "apache SNI enabled"
`onChange` reloaded
multiSSL = check (doesDirectoryExist "/etc/apache2/conf.d") $
"/etc/apache2/conf.d/ssl" `File.hasContent`
[ "NameVirtualHost *:443"
, "SSLStrictSNIVHostCheck off"
]
`describe` "apache SNI enabled"
`onChange` reloaded
-- | Config file fragment that can be inserted into a <Directory>
-- stanza to allow global read access to the directory.

View File

@ -8,18 +8,26 @@ import Utility.FileMode
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
-- directory. Note that the Desc must be unique, as it is used for the
-- cron.d/ filename.
-- | 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
-- cron job filename.
--
-- 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
-- job file.
--
-- 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)
[ cronjobfile `File.hasContent`
[ "# Generated by propellor"
@ -27,8 +35,15 @@ job desc times user cddir command = combineProperties ("cronned " ++ desc)
, "SHELL=/bin/sh"
, "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
-- prettier in emails, and also allows running the job manually.
, scriptfile `File.hasContent`
@ -44,7 +59,12 @@ job desc times user cddir command = combineProperties ("cronned " ++ desc)
`requires` Apt.installed ["util-linux", "moreutils"]
where
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"
name = map sanitize desc
sanitize c
@ -52,10 +72,10 @@ job desc times user cddir command = combineProperties ("cronned " ++ desc)
| otherwise = '_'
-- | 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
("nice ionice -c 3 sh -c " ++ shellEscape command)
-- | Installs a cron job to run propellor.
runPropellor :: CronTimes -> Property NoInfo
runPropellor :: Times -> Property NoInfo
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
-- | 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 = hasPrivContent' writeFileProtected

View File

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

View File

@ -2,9 +2,18 @@ module Propellor.Property.HostingProvider.Linode where
import Propellor
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
-- Debian kernels compressed with xz. This sets up pv-grub chaing to enable
-- it.
chainPVGrub :: Grub.TimeoutSecs -> Property NoInfo
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)
--
-- 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
`requires` restored dir params
@ -46,7 +46,7 @@ backup dir crontimes params numclients =
--
-- The gpg secret key will be automatically imported
-- 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 =
backup dir crontimes params' numclients
`requires` Gpg.keyImported keyid "root"
@ -54,7 +54,7 @@ backupEncrypted dir crontimes params numclients keyid =
params' = ("--encrypt-with=" ++ Gpg.getGpgKeyId keyid) : params
-- | 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
where
desc = dir ++ " backed up by obnam"

View File

@ -4,8 +4,9 @@ module Propellor.Property.Postfix where
import Propellor
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.User as User
import qualified Data.Map as M
import Data.List
@ -103,7 +104,7 @@ mainCfIsSet name = do
-- Note that multiline configurations that continue onto the next line
-- are not currently supported.
dedupMainCf :: Property NoInfo
dedupMainCf = fileProperty "postfix main.cf dedupped" dedupCf mainCfFile
dedupMainCf = File.fileProperty "postfix main.cf dedupped" dedupCf mainCfFile
dedupCf :: [String] -> [String]
dedupCf ls =
@ -125,3 +126,33 @@ dedupCf ls =
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
_ -> 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.File as File
import qualified Propellor.Property.Docker as Docker
import Propellor.Property.Cron (CronTimes)
import Propellor.Property.Cron (Times)
builduser :: UserName
builduser = "builder"
@ -25,7 +25,7 @@ builddir = gitbuilderdir </> "build"
type TimeOut = String -- eg, 5h
autobuilder :: Architecture -> CronTimes -> TimeOut -> Property HasInfo
autobuilder :: Architecture -> Times -> TimeOut -> Property HasInfo
autobuilder arch crontimes timeout = combineProperties "gitannexbuilder" $ props
& Apt.serviceInstalledRunning "cron"
& Cron.niceJob "gitannexbuilder" crontimes builduser gitbuilderdir
@ -102,10 +102,10 @@ standardAutoBuilderContainer dockerImage arch buildminute timeout = Docker.conta
& User.accountFor builduser
& tree arch
& buildDepsApt
& autobuilder arch (show buildminute ++ " * * * *") timeout
& autobuilder arch (Cron.Times $ show buildminute ++ " * * * *") timeout
& Docker.tweaked
androidAutoBuilderContainer :: (System -> Docker.Image) -> Cron.CronTimes -> TimeOut -> Docker.Container
androidAutoBuilderContainer :: (System -> Docker.Image) -> Times -> TimeOut -> Docker.Container
androidAutoBuilderContainer dockerImage crontimes timeout =
androidContainer dockerImage "android-git-annex-builder" (tree "android") builddir
& Apt.unattendedUpgrades
@ -166,7 +166,7 @@ armelCompanionContainer dockerImage = Docker.container "armel-git-annex-builder-
& Ssh.authorizedKeys builduser (Context "armel-git-annex-builder")
& 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"
(dockerImage $ System (Debian Unstable) "armel")
& os (System (Debian Testing) "armel")

View File

@ -24,6 +24,7 @@ import Data.String.Utils
oldUseNetServer :: [Host] -> Property HasInfo
oldUseNetServer hosts = propertyList "olduse.net server" $ props
& Apt.installed ["leafnode"]
& oldUseNetInstalled "oldusenet-server"
& Obnam.latestVersion
& oldUseNetBackup
@ -32,7 +33,6 @@ oldUseNetServer hosts = propertyList "olduse.net server" $ props
removeDirectoryRecursive newsspool
createSymbolicLink (datadir </> "news") newsspool
)
& Apt.installed ["leafnode"]
& "/etc/news/leafnode/config" `File.hasContent`
[ "# olduse.net configuration (deployed by propellor)"
, "expire = 1000000" -- no expiry via texpire
@ -45,8 +45,8 @@ oldUseNetServer hosts = propertyList "olduse.net server" $ props
& Apt.serviceInstalledRunning "openbsd-inetd"
& File.notPresent "/etc/cron.daily/leafnode"
& File.notPresent "/etc/cron.d/leafnode"
& Cron.niceJob "oldusenet-expire" "11 1 * * *" "news" newsspool expirecommand
& Cron.niceJob "oldusenet-uucp" "*/5 * * * *" "news" "/" uucpcommand
& Cron.niceJob "oldusenet-expire" (Cron.Times "11 1 * * *") "news" newsspool expirecommand
& Cron.niceJob "oldusenet-uucp" (Cron.Times "*/5 * * * *") "news" "/" uucpcommand
& Apache.siteEnabled "nntp.olduse.net" nntpcfg
where
newsspool = "/var/spool/news"
@ -65,12 +65,14 @@ oldUseNetServer hosts = propertyList "olduse.net server" $ props
, " </Directory>"
]
oldUseNetBackup = Obnam.backup datadir "33 4 * * *"
oldUseNetBackup = Obnam.backup datadir (Cron.Times "33 4 * * *")
[ "--repository=sftp://2318@usw-s002.rsync.net/~/olduse.net"
, "--client-name=spool"
, "--ssh-key=" ++ keyfile
] 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"
keyfile = "/root/.ssh/olduse.net.key"
oldUseNetShellBox :: Property HasInfo
oldUseNetShellBox = propertyList "olduse.net shellbox" $ props
@ -113,12 +115,12 @@ mumbleServer :: [Host] -> Property HasInfo
mumbleServer hosts = combineProperties hn $ props
& Apt.serviceInstalledRunning "mumble-server"
& Obnam.latestVersion
& Obnam.backup "/var/lib/mumble-server" "55 5 * * *"
[ "--repository=sftp://joey@usbackup.kitenet.net/~/lib/backup/" ++ hn ++ ".obnam"
& Obnam.backup "/var/lib/mumble-server" (Cron.Times "55 5 * * *")
[ "--repository=sftp://2318@usw-s002.rsync.net/~/" ++ hn ++ ".obnam"
, "--client-name=mumble"
] Obnam.OnlyClient
`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"])
where
hn = "mumble.debian.net"
@ -129,8 +131,8 @@ obnamLowMem = combineProperties "obnam tuned for low memory use"
, "/etc/obnam.conf" `File.containsLines`
[ "[config]"
, "# Suggested by liw to keep Obnam memory consumption down (at some speed cost)."
, "upload-queue-size = 128"
, "lru-size = 128"
, "upload-queue-size = 96"
, "lru-size = 96"
]
]
@ -138,20 +140,20 @@ obnamLowMem = combineProperties "obnam tuned for low memory use"
gitServer :: [Host] -> Property HasInfo
gitServer hosts = propertyList "git.kitenet.net setup" $ props
& 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"
, "--ssh-key=" ++ sshkey
, "--client-name=wren" -- historical
] 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.authorizedKeys "family" (Context "git.kitenet.net")
`requires` User.accountFor "family"
& Apt.installed ["git", "rsync", "gitweb"]
-- backport avoids channel flooding on branch merge
& Apt.installedBackport ["kgb-client"]
-- backport supports ssh event notification
& Apt.installedBackport ["git-annex"]
& Apt.installed ["git-annex"]
& Apt.installed ["kgb-client"]
& File.hasPrivContentExposed "/etc/kgb-bot/kgb-client.conf" anyContext
`requires` File.dirExists "/etc/kgb-bot/"
& Git.daemonRunning "/srv/git"
& "/etc/gitweb.conf" `File.containsLines`
[ "$projectroot = '/srv/git';"
@ -168,6 +170,7 @@ gitServer hosts = propertyList "git.kitenet.net setup" $ props
& website "git.joeyh.name"
& Apache.modEnabled "cgi"
where
sshkey = "/root/.ssh/git.kitenet.net.key"
website hn = apacheSite hn True
[ " DocumentRoot /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"
, " AddHandler cgi-script .cgi"
, " DirectoryIndex index.cgi"
, Apache.allowAll
, " </Directory>"
, ""
, " 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
setupscript =
[ "cd " ++ shellEscape dir
, "git config annex.uuid " ++ shellEscape uuid
, "git annex reinit " ++ shellEscape uuid
] ++ map addremote remotes ++
[ "git annex get"
, "git update-server-info"
@ -217,14 +221,14 @@ annexWebSite origin hn uuid remotes = propertyList (hn ++" website using git-ann
, " <Directory /srv/web/"++hn++">"
, " Options FollowSymLinks"
, " AllowOverride None"
, Apache.allowAll
, " </Directory>"
, " <Directory /srv/web/"++hn++">"
, " Options Indexes FollowSymLinks ExecCGI"
, " AllowOverride None"
, " AddHandler cgi-script .cgi"
, " DirectoryIndex index.html index.cgi"
, " Order allow,deny"
, " allow from all"
, Apache.allowAll
, " </Directory>"
]
@ -252,8 +256,7 @@ apachecfg hn withssl middle
, " <Directory \"/usr/share/apache2/icons\">"
, " Options Indexes MultiViews"
, " AllowOverride None"
, " Order allow,deny"
, " Allow from all"
, Apache.allowAll
, " </Directory>"
, "</VirtualHost>"
]
@ -288,6 +291,22 @@ gitAnnexDistributor = combineProperties "git-annex distributor, including rsync
, 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.
twitRss :: Property HasInfo
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"
where
dir = "/srv/web/tmp.kitenet.net/twitrss"
crontime = "15 * * * *"
crontime = Cron.Times "15 * * * *"
feed url desc = Cron.job desc crontime "joey" dir $
"./twitRss " ++ shellEscape url ++ " > " ++ shellEscape ("../" ++ desc ++ ".rss")
compiled = userScriptProperty "joey"
@ -311,9 +330,8 @@ twitRss = combineProperties "twitter rss" $ props
]
-- Work around for expired ssl cert.
-- (no longer expired, TODO remove this and change urls)
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"
ircBouncer :: Property HasInfo
@ -323,7 +341,7 @@ ircBouncer = propertyList "IRC bouncer" $ props
& File.dirExists (takeDirectory conf)
& File.hasPrivContent conf anyContext
& 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
& trivial (userScriptProperty "znc" ["znc || true"])
`describe` "znc running"
@ -347,9 +365,9 @@ githubBackup :: Property HasInfo
githubBackup = propertyList "github-backup box" $ props
& Apt.installed ["github-backup", "moreutils"]
& githubKeys
& Cron.niceJob "github-backup run" "30 4 * * *" "joey"
& Cron.niceJob "github-backup run" (Cron.Times "30 4 * * *") "joey"
"/home/joey/lib/backup" backupcmd
& Cron.niceJob "gitriddance" "30 4 * * *" "joey"
& Cron.niceJob "gitriddance" (Cron.Times "30 4 * * *") "joey"
"/home/joey/lib/backup" gitriddancecmd
where
backupcmd = intercalate "&&" $
@ -385,17 +403,17 @@ githubMirrors =
plzuseurl u = "please submit changes to " ++ u ++ " instead of using github pull requests"
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"
`requires` Ssh.knownHost hosts "usw-s002.rsync.net" "joey"
backupsBackedupTo :: [Host] -> HostName -> FilePath -> Property NoInfo
backupsBackedupTo hosts desthost destdir = Cron.niceJob desc
"1 1 * * 3" "joey" "/" cmd
`requires` Ssh.knownHost hosts desthost "joey"
backupsBackedupFrom :: [Host] -> HostName -> FilePath -> Property NoInfo
backupsBackedupFrom hosts srchost destdir = Cron.niceJob desc
(Cron.Times "@reboot") "joey" "/" cmd
`requires` Ssh.knownHost hosts srchost "joey"
where
desc = "backups copied to " ++ desthost ++ " weekly"
cmd = "rsync -az --delete /home/joey/lib/backup " ++ desthost ++ ":" ++ destdir
desc = "backups copied from " ++ srchost ++ " on boot"
cmd = "rsync -az --bwlimit=300K --partial --delete " ++ srchost ++ ":lib/backup/ " ++ destdir </> srchost
obnamRepos :: [String] -> Property NoInfo
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"
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"
"xargs git-annex importfeed -c annex.genmetadata=true < feeds; mr --quiet update"
`requires` Apt.installed ["git-annex", "myrepos"]
@ -450,6 +468,8 @@ kiteMailServer = propertyList "kitenet.net mail server" $ props
& dkimInstalled
& Postfix.saslAuthdInstalled
& Apt.installed ["maildrop"]
& "/etc/maildroprc" `File.hasContent`
[ "# 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."
, "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."
, "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"
, "smtpd_milters = unix:/spamass/spamass.sock unix:amavis/amavis.sock inet:localhost:8891"

View File

@ -12,6 +12,7 @@ module Propellor.Property.Ssh (
pubKey,
getPubKey,
keyImported,
keyImported',
knownHost,
authorizedKeys,
listenPort
@ -147,13 +148,25 @@ getPubKey = asks (_sshPubKey . hostInfo)
-- | Sets up a user with a ssh private key and public key pair from the
-- PrivData.
--
-- If the user already has a private/public key, it is left unchanged.
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 (SshPrivKey keytype user) (install writeFileProtected "")
]
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 ->
property desc $ getkey a
install writer ext key = do
@ -168,9 +181,11 @@ keyImported keytype user context = combineProperties desc
, File.ownerGroup (takeDirectory f) user user
]
)
keyfile ext = do
home <- homeDirectory <$> getUserEntryForName user
return $ home </> ".ssh" </> "id_" ++ fromKeyType keytype ++ ext
keyfile ext = case dest of
Nothing -> do
home <- homeDirectory <$> getUserEntryForName user
return $ home </> ".ssh" </> "id_" ++ fromKeyType keytype ++ ext
Just f -> return $ f ++ ext
fromKeyType :: SshKeyType -> String
fromKeyType SshRsa = "rsa"
@ -178,7 +193,7 @@ fromKeyType SshDsa = "dsa"
fromKeyType SshEcdsa = "ecdsa"
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.
knownHost :: [Host] -> HostName -> UserName -> Property NoInfo
knownHost hosts hn user = property desc $
@ -192,6 +207,7 @@ knownHost hosts hn user = property desc $
, f `File.containsLines`
(map (\k -> hn ++ " " ++ k) (M.elems m))
, File.ownerGroup f user user
, File.ownerGroup (takeDirectory f) user user
]
go _ = do
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.
-- Any other lines in the file are preserved as-is.
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
ensureProperty $
f `File.containsLine` l
ensureProperty $ combineProperties desc
[ f `File.containsLine` l
`requires` File.dirExists (takeDirectory f)
`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
-- ports it is configured to listen on.

View File

@ -7,19 +7,78 @@ import qualified Propellor.Property.Service as Service
import Utility.FileMode
import System.Posix.Files
import Data.Char
type HiddenServiceName = String
type NodeName = String
-- | Sets up a tor bridge. (Not a relay or exit node.)
--
-- Uses port 443
isBridge :: Property NoInfo
isBridge = setup `requires` Apt.installed ["tor"]
isBridge = isBridge' []
isBridge' :: [String] -> Property NoInfo
isBridge' extraconfig = server config
`describe` "tor bridge"
where
setup = mainConfig `File.hasContent`
[ "SocksPort 0"
, "ORPort 443"
, "BridgeRelay 1"
config =
[ "BridgeRelay 1"
, "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 hn port = hiddenServiceHostName prop
@ -80,3 +139,14 @@ varRun = "/var/run/tor"
user :: UserName
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