From a1f61e09b8d72ef4d4ee8490b9b228dafd8b3d1d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Jan 2015 19:10:28 -0400 Subject: stub signedPrimary --- src/Propellor/Property/Dns.hs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index f351804c..20530f26 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -1,6 +1,7 @@ module Propellor.Property.Dns ( module Propellor.Types.Dns, primary, + signedPrimary, secondary, secondaryFor, mkSOA, @@ -17,6 +18,8 @@ import Propellor.Types.Dns import Propellor.Property.File import qualified Propellor.Property.Apt as Apt import qualified Propellor.Property.Service as Service +import Propellor.Property.Scheduled +import Propellor.Property.DnsSec import Utility.Applicative import qualified Data.Map as M @@ -97,6 +100,30 @@ primary hosts domain soa rs = RevertableProperty setup cleanup z = zone { zSOA = (zSOA zone) { sSerial = oldserial } } in z /= oldzone || oldserial < sSerial (zSOA zone) +-- | Primary dns server for a domain, secured with DNSSEC. +-- +-- This is like `primary`, except the resulting zone +-- file is signed. +-- The Zone Signing Key (ZSK) and Key Signing Key (KSK) +-- used in signing it are taken from the PrivData. +-- +-- As a side effect of signing the zone, a +-- +-- file will be created. This file contains the DS records +-- which need to be communicated to your domain registrar +-- to make DNSSEC be used for your domain. Doing so is outside +-- the scope of propellor (currently). See for example the tutorial +-- +-- +-- The 'Recurrance' controls how frequently the signature +-- should be regenerated, using a new random salt, to prevent +-- zone walking attacks. `Daily` is a reasonable choice. +signedPrimary :: Recurrance -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty +signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup + where + setup = undefined + cleanup = undefined + -- | Secondary dns server for a domain. -- -- The primary server is determined by looking at the properties of other -- cgit v1.3-2-g0d8e From 8172f243d73f0c7f7231d03c3561c3da5a7ad0d4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 12:44:05 -0400 Subject: DNS WIP --- src/Propellor/Info.hs | 1 + src/Propellor/PrivData/Paths.hs | 2 +- src/Propellor/Property.hs | 3 +- src/Propellor/Property/Dns.hs | 50 +++++++++++++++++++++++------ src/Propellor/Property/DnsSec.hs | 69 +++++++++++++++++++++++++++++++++++++--- src/Propellor/Types/Dns.hs | 1 + 6 files changed, 109 insertions(+), 17 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Info.hs b/src/Propellor/Info.hs index 0437f8ec..3af3fc15 100644 --- a/src/Propellor/Info.hs +++ b/src/Propellor/Info.hs @@ -64,6 +64,7 @@ addDNS r = pureInfoProperty (rdesc r) $ mempty { _dns = S.singleton r } rdesc (NS d) = unwords ["NS", ddesc d] rdesc (TXT s) = unwords ["TXT", s] rdesc (SRV x y z d) = unwords ["SRV", show x, show y, show z, ddesc d] + rdesc (INCLUDE f) = unwords ["$INCLUDE", f] ddesc (AbsDomain domain) = domain ddesc (RelDomain domain) = domain diff --git a/src/Propellor/PrivData/Paths.hs b/src/Propellor/PrivData/Paths.hs index 9f791b76..3d0d8a58 100644 --- a/src/Propellor/PrivData/Paths.hs +++ b/src/Propellor/PrivData/Paths.hs @@ -3,7 +3,7 @@ module Propellor.PrivData.Paths where import System.FilePath privDataDir :: FilePath -privDataDir = "privdata.joey" +privDataDir = "privdata" privDataFile :: FilePath privDataFile = privDataDir "privdata.gpg" diff --git a/src/Propellor/Property.hs b/src/Propellor/Property.hs index 37fd90d6..c0878fb6 100644 --- a/src/Propellor/Property.hs +++ b/src/Propellor/Property.hs @@ -26,8 +26,7 @@ propertyList :: Desc -> [Property] -> Property propertyList desc ps = Property desc (ensureProperties ps) (combineInfos ps) -- | Combines a list of properties, resulting in one property that --- ensures each in turn. Does not stop on failure; does propigate --- overall success/failure. +-- ensures each in turn. Stops if a property fails. combineProperties :: Desc -> [Property] -> Property combineProperties desc ps = Property desc (go ps NoChange) (combineInfos ps) where diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index 20530f26..89180963 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -56,18 +56,18 @@ import Data.List primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty primary hosts domain soa rs = RevertableProperty setup cleanup where - setup = withwarnings (check needupdate baseprop) - `requires` servingZones + setup = setupPrimary hosts domain soa rs + `onChange` Service.reloaded "bind9" + cleanup = cleanupPrimary domain `onChange` Service.reloaded "bind9" - cleanup = check (doesFileExist zonefile) $ - property ("removed dns primary for " ++ domain) - (makeChange $ removeZoneFile zonefile) - `requires` namedConfWritten - `onChange` Service.reloaded "bind9" +setupPrimary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property +setupPrimary hosts domain soa rs = withwarnings (check needupdate baseprop) + `requires` servingZones + where (partialzone, zonewarnings) = genZone hosts domain soa zone = partialzone { zHosts = zHosts partialzone ++ rs } - zonefile = "/etc/bind/propellor/db." ++ domain + zonefile = zoneFile domain baseprop = Property ("dns primary for " ++ domain) (makeChange $ writeZoneFile zone zonefile) (addNamedConf conf) @@ -100,6 +100,18 @@ primary hosts domain soa rs = RevertableProperty setup cleanup z = zone { zSOA = (zSOA zone) { sSerial = oldserial } } in z /= oldzone || oldserial < sSerial (zSOA zone) + +cleanupPrimary :: Domain -> Property +cleanupPrimary domain = check (doesFileExist zonefile) $ + property ("removed dns primary for " ++ domain) + (makeChange $ removeZoneFile zonefile) + `requires` namedConfWritten + where + zonefile = zoneFile domain + +zoneFile :: Domain -> FilePath +zoneFile domain = "/etc/bind/propellor/db." ++ domain + -- | Primary dns server for a domain, secured with DNSSEC. -- -- This is like `primary`, except the resulting zone @@ -121,8 +133,24 @@ primary hosts domain soa rs = RevertableProperty setup cleanup signedPrimary :: Recurrance -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup where - setup = undefined - cleanup = undefined + -- TODO put signed zone file in named.conf. + -- TODO enable dnssec options. + -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; + -- TODO if keys change, resign zone file. + -- TODO write to entirely different files than does primary, + -- so that primary can be reverted and signedPrimary enabled, + -- or vice-versa, without conflicts. + setup = setupPrimary hosts domain soa rs' + `onChange` toProp (zoneSigned domain (zoneFile domain)) + `onChange` Service.reloaded "bind9" + + cleanup = cleanupPrimary domain + `onChange` toProp (revert (zoneSigned domain (zoneFile domain))) + `onChange` Service.reloaded "bind9" + + -- Include the public keys into the zone file. + rs' = include PubKSK : include PubZSK : rs + include k = (RootDomain, INCLUDE (keyFn domain k)) -- | Secondary dns server for a domain. -- @@ -243,6 +271,7 @@ rField (MX _ _) = "MX" rField (NS _) = "NS" rField (TXT _) = "TXT" rField (SRV _ _ _ _) = "SRV" +rField (INCLUDE _) = "$INCLUDE" rValue :: Record -> String rValue (Address (IPv4 addr)) = addr @@ -256,6 +285,7 @@ rValue (SRV priority weight port target) = unwords , show port , dValue target ] +rValue (INCLUDE f) = f rValue (TXT s) = [q] ++ filter (/= q) s ++ [q] where q = '"' diff --git a/src/Propellor/Property/DnsSec.hs b/src/Propellor/Property/DnsSec.hs index 55a447a1..201cc003 100644 --- a/src/Propellor/Property/DnsSec.hs +++ b/src/Propellor/Property/DnsSec.hs @@ -1,7 +1,7 @@ module Propellor.Property.DnsSec where import Propellor -import Propellor.Property.File +import qualified Propellor.Property.File as File -- | Puts the DNSSEC key files in place from PrivData. -- @@ -14,10 +14,13 @@ keysInstalled domain = RevertableProperty setup cleanup map installkey keys cleanup = propertyList "DNSSEC keys removed" $ - map (notPresent . keyFn domain) keys + map (File.notPresent . keyFn domain) keys - installkey k = (if isPublic k then hasPrivContentExposedFrom else hasPrivContentFrom) - (keysrc k) (keyFn domain k) (Context domain) + installkey k = writer (keysrc k) (keyFn domain k) (Context domain) + where + writer + | isPublic k = File.hasPrivContentExposedFrom + | otherwise = File.hasPrivContentFrom keys = [ PubZSK, PrivZSK, PubKSK, PrivKSK ] @@ -30,6 +33,64 @@ keysInstalled domain = RevertableProperty setup cleanup else "dnssec-keygen -f KSK -a RSASHA256 -b 4096 -n ZONE " ++ domain ] +-- | Uses dnssec-signzone to sign a domain's zone file. +-- +-- signedPrimary uses this, so this property does not normally need to be +-- used directly. +zoneSigned :: Domain -> FilePath -> RevertableProperty +zoneSigned domain zonefile = RevertableProperty setup cleanup + where + setup = check needupdate (forceZoneSigned domain zonefile) + `requires` toProp (keysInstalled domain) + + cleanup = combineProperties ("removed signed zone for " ++ domain) + [ File.notPresent signedzonefile + , File.notPresent dssetfile + , toProp (revert (keysInstalled domain)) + ] + + signedzonefile = dir domain ++ ".signed" + dssetfile = dir "-" ++ domain ++ "." + dir = takeDirectory zonefile + + -- Need to update the signed zone if the zone file + -- has a newer timestamp. + needupdate = do + v <- catchMaybeIO $ getModificationTime signedzonefile + case v of + Nothing -> return True + Just t1 -> do + t2 <- getModificationTime zonefile + return (t2 >= t1) + +forceZoneSigned :: Domain -> FilePath -> Property +forceZoneSigned domain zonefile = property ("zone signed for " ++ domain) $ liftIO $ do + salt <- take 16 <$> saltSha1 + let p = proc "dnssec-signzone" + [ "-A" + , "-3", salt + , "-N", "keep" + , "-o", domain + , zonefile + -- the ordering of these key files does not matter + , keyFn domain PubZSK + , keyFn domain PubKSK + ] + -- Run in the same directory as the zonefile, so it will + -- write the dsset file there. + (_, _, _, h) <- createProcess $ + p { cwd = Just (takeDirectory zonefile) } + ifM (checkSuccessProcess h) + ( return MadeChange + , return FailedChange + ) + +saltSha1 :: IO String +saltSha1 = readProcess "sh" + [ "-c" + , "head -c 1024 /dev/urandom | sha1sum | cut -d ' ' -f 1" + ] + -- | The file used for a given key. keyFn :: Domain -> DnsSecKey -> FilePath keyFn domain k = "/etc/bind/propellor" diff --git a/src/Propellor/Types/Dns.hs b/src/Propellor/Types/Dns.hs index 5e9666d8..2fbf51e5 100644 --- a/src/Propellor/Types/Dns.hs +++ b/src/Propellor/Types/Dns.hs @@ -62,6 +62,7 @@ data Record | NS BindDomain | TXT String | SRV Word16 Word16 Word16 BindDomain + | INCLUDE FilePath deriving (Read, Show, Eq, Ord) getIPAddr :: Record -> Maybe IPAddr -- cgit v1.3-2-g0d8e From d6c8ddb955707cd73f66fcb662ea4616c5715d39 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 13:13:06 -0400 Subject: resign zone if keys change --- src/Propellor/Property/Dns.hs | 1 - src/Propellor/Property/DnsSec.hs | 13 ++++++++----- src/Propellor/Types/PrivData.hs | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index 89180963..38e98eac 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -136,7 +136,6 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup -- TODO put signed zone file in named.conf. -- TODO enable dnssec options. -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; - -- TODO if keys change, resign zone file. -- TODO write to entirely different files than does primary, -- so that primary can be reverted and signedPrimary enabled, -- or vice-versa, without conflicts. diff --git a/src/Propellor/Property/DnsSec.hs b/src/Propellor/Property/DnsSec.hs index 201cc003..ba9c2a1b 100644 --- a/src/Propellor/Property/DnsSec.hs +++ b/src/Propellor/Property/DnsSec.hs @@ -53,15 +53,18 @@ zoneSigned domain zonefile = RevertableProperty setup cleanup dssetfile = dir "-" ++ domain ++ "." dir = takeDirectory zonefile - -- Need to update the signed zone if the zone file - -- has a newer timestamp. + -- Need to update the signed zone file if the zone file or + -- any of the keys have a newer timestamp. needupdate = do v <- catchMaybeIO $ getModificationTime signedzonefile case v of Nothing -> return True - Just t1 -> do - t2 <- getModificationTime zonefile - return (t2 >= t1) + Just t1 -> anyM (newerthan t1) $ + zonefile : map (keyFn domain) [minBound..maxBound] + + newerthan t1 f = do + t2 <- getModificationTime f + return (t2 >= t1) forceZoneSigned :: Domain -> FilePath -> Property forceZoneSigned domain zonefile = property ("zone signed for " ++ domain) $ liftIO $ do diff --git a/src/Propellor/Types/PrivData.hs b/src/Propellor/Types/PrivData.hs index 636c9658..d6941a77 100644 --- a/src/Propellor/Types/PrivData.hs +++ b/src/Propellor/Types/PrivData.hs @@ -104,4 +104,4 @@ data DnsSecKey | PrivZSK -- ^ DNSSEC Zone Signing Key (private) | PubKSK -- ^ DNSSEC Key Signing Key (public) | PrivKSK -- ^ DNSSEC Key Signing Key (private) - deriving (Read, Show, Ord, Eq) + deriving (Read, Show, Ord, Eq, Bounded, Enum) -- cgit v1.3-2-g0d8e From e67901a77b0bdde7ea4d37083e770c723018dc32 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 13:22:23 -0400 Subject: use separate directory for dnssec files --- src/Propellor/Property/Dns.hs | 39 +++++++++++++++++++-------------------- src/Propellor/Property/DnsSec.hs | 2 +- 2 files changed, 20 insertions(+), 21 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index 38e98eac..47f39718 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -56,18 +56,20 @@ import Data.List primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty primary hosts domain soa rs = RevertableProperty setup cleanup where - setup = setupPrimary hosts domain soa rs + setup = setupPrimary zonefile hosts domain soa rs `onChange` Service.reloaded "bind9" - cleanup = cleanupPrimary domain + cleanup = cleanupPrimary zonefile domain `onChange` Service.reloaded "bind9" -setupPrimary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property -setupPrimary hosts domain soa rs = withwarnings (check needupdate baseprop) + zonefile = "/etc/bind/propellor/db." ++ domain + +setupPrimary :: FilePath -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property +setupPrimary zonefile hosts domain soa rs = + withwarnings (check needupdate baseprop) `requires` servingZones where (partialzone, zonewarnings) = genZone hosts domain soa zone = partialzone { zHosts = zHosts partialzone ++ rs } - zonefile = zoneFile domain baseprop = Property ("dns primary for " ++ domain) (makeChange $ writeZoneFile zone zonefile) (addNamedConf conf) @@ -101,16 +103,11 @@ setupPrimary hosts domain soa rs = withwarnings (check needupdate baseprop) in z /= oldzone || oldserial < sSerial (zSOA zone) -cleanupPrimary :: Domain -> Property -cleanupPrimary domain = check (doesFileExist zonefile) $ +cleanupPrimary :: FilePath -> Domain -> Property +cleanupPrimary zonefile domain = check (doesFileExist zonefile) $ property ("removed dns primary for " ++ domain) (makeChange $ removeZoneFile zonefile) `requires` namedConfWritten - where - zonefile = zoneFile domain - -zoneFile :: Domain -> FilePath -zoneFile domain = "/etc/bind/propellor/db." ++ domain -- | Primary dns server for a domain, secured with DNSSEC. -- @@ -133,24 +130,26 @@ zoneFile domain = "/etc/bind/propellor/db." ++ domain signedPrimary :: Recurrance -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup where - -- TODO put signed zone file in named.conf. -- TODO enable dnssec options. -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; - -- TODO write to entirely different files than does primary, - -- so that primary can be reverted and signedPrimary enabled, - -- or vice-versa, without conflicts. - setup = setupPrimary hosts domain soa rs' - `onChange` toProp (zoneSigned domain (zoneFile domain)) + setup = setupPrimary zonefile hosts domain soa rs' + `onChange` toProp (zoneSigned domain zonefile) `onChange` Service.reloaded "bind9" - cleanup = cleanupPrimary domain - `onChange` toProp (revert (zoneSigned domain (zoneFile domain))) + cleanup = cleanupPrimary zonefile domain + `onChange` toProp (revert (zoneSigned domain zonefile)) `onChange` Service.reloaded "bind9" -- Include the public keys into the zone file. rs' = include PubKSK : include PubZSK : rs include k = (RootDomain, INCLUDE (keyFn domain k)) + -- Put DNSSEC zone files in a different directory than is used for + -- the regular ones. This allows 'primary' to be reverted and + -- 'signedPrimary' enabled, without the reverted property stomping + -- on the new one's settings. + zonefile = "/etc/bind/propellor/dnssec/db." ++ domain + -- | Secondary dns server for a domain. -- -- The primary server is determined by looking at the properties of other diff --git a/src/Propellor/Property/DnsSec.hs b/src/Propellor/Property/DnsSec.hs index ba9c2a1b..f76a28ff 100644 --- a/src/Propellor/Property/DnsSec.hs +++ b/src/Propellor/Property/DnsSec.hs @@ -96,7 +96,7 @@ saltSha1 = readProcess "sh" -- | The file used for a given key. keyFn :: Domain -> DnsSecKey -> FilePath -keyFn domain k = "/etc/bind/propellor" +keyFn domain k = "/etc/bind/propellor/dnssec" "K" ++ domain ++ "." ++ show k ++ keyExt k -- | These are the extensions that dnssec-keygen looks for. -- cgit v1.3-2-g0d8e From bf34d6f423bd2da76938dfdc1cf4525dc17b97c5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 13:42:01 -0400 Subject: propellor spin --- src/Propellor/Property/Dns.hs | 10 +++++----- src/Propellor/Property/DnsSec.hs | 9 ++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index 47f39718..062b278b 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -56,15 +56,15 @@ import Data.List primary :: [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty primary hosts domain soa rs = RevertableProperty setup cleanup where - setup = setupPrimary zonefile hosts domain soa rs + setup = setupPrimary zonefile id hosts domain soa rs `onChange` Service.reloaded "bind9" cleanup = cleanupPrimary zonefile domain `onChange` Service.reloaded "bind9" zonefile = "/etc/bind/propellor/db." ++ domain -setupPrimary :: FilePath -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property -setupPrimary zonefile hosts domain soa rs = +setupPrimary :: FilePath -> (FilePath -> FilePath) -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> Property +setupPrimary zonefile mknamedconffile hosts domain soa rs = withwarnings (check needupdate baseprop) `requires` servingZones where @@ -79,7 +79,7 @@ setupPrimary zonefile hosts domain soa rs = conf = NamedConf { confDomain = domain , confDnsServerType = Master - , confFile = zonefile + , confFile = mknamedconffile zonefile , confMasters = [] , confAllowTransfer = nub $ concatMap (\h -> hostAddresses h hosts) $ @@ -132,7 +132,7 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup where -- TODO enable dnssec options. -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; - setup = setupPrimary zonefile hosts domain soa rs' + setup = setupPrimary zonefile signedZoneFile hosts domain soa rs' `onChange` toProp (zoneSigned domain zonefile) `onChange` Service.reloaded "bind9" diff --git a/src/Propellor/Property/DnsSec.hs b/src/Propellor/Property/DnsSec.hs index f76a28ff..47fa9b32 100644 --- a/src/Propellor/Property/DnsSec.hs +++ b/src/Propellor/Property/DnsSec.hs @@ -44,19 +44,18 @@ zoneSigned domain zonefile = RevertableProperty setup cleanup `requires` toProp (keysInstalled domain) cleanup = combineProperties ("removed signed zone for " ++ domain) - [ File.notPresent signedzonefile + [ File.notPresent (signedZoneFile zonefile) , File.notPresent dssetfile , toProp (revert (keysInstalled domain)) ] - signedzonefile = dir domain ++ ".signed" dssetfile = dir "-" ++ domain ++ "." dir = takeDirectory zonefile -- Need to update the signed zone file if the zone file or -- any of the keys have a newer timestamp. needupdate = do - v <- catchMaybeIO $ getModificationTime signedzonefile + v <- catchMaybeIO $ getModificationTime (signedZoneFile zonefile) case v of Nothing -> return True Just t1 -> anyM (newerthan t1) $ @@ -110,3 +109,7 @@ isPublic k = k `elem` [PubZSK, PubKSK] isZoneSigningKey :: DnsSecKey -> Bool isZoneSigningKey k = k `elem` [PubZSK, PrivZSK] + +-- | dnssec-signzone makes a .signed file +signedZoneFile :: FilePath -> FilePath +signedZoneFile zonefile = zonefile ++ ".signed" -- cgit v1.3-2-g0d8e From ce7f14b9b3f4e00ef0c44537ec94fa8855308764 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 13:52:59 -0400 Subject: propellor spin --- src/Propellor/Property/Dns.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index 062b278b..27f81f62 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -132,8 +132,10 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup where -- TODO enable dnssec options. -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; - setup = setupPrimary zonefile signedZoneFile hosts domain soa rs' - `onChange` toProp (zoneSigned domain zonefile) + setup = combineProperties ("dns primary for " ++ domain ++ " (signed)") + [ setupPrimary zonefile signedZoneFile hosts domain soa rs' + , toProp (zoneSigned domain zonefile) + ] `onChange` Service.reloaded "bind9" cleanup = cleanupPrimary zonefile domain -- cgit v1.3-2-g0d8e From f36443755e9c151d7d93b172fb2260b007ec483f Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 14:05:42 -0400 Subject: propellor spin --- src/Propellor/Info.hs | 1 - src/Propellor/Property/Dns.hs | 8 +------- src/Propellor/Property/DnsSec.hs | 14 ++++++++++++-- src/Propellor/Types/Dns.hs | 1 - 4 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Info.hs b/src/Propellor/Info.hs index 3af3fc15..0437f8ec 100644 --- a/src/Propellor/Info.hs +++ b/src/Propellor/Info.hs @@ -64,7 +64,6 @@ addDNS r = pureInfoProperty (rdesc r) $ mempty { _dns = S.singleton r } rdesc (NS d) = unwords ["NS", ddesc d] rdesc (TXT s) = unwords ["TXT", s] rdesc (SRV x y z d) = unwords ["SRV", show x, show y, show z, ddesc d] - rdesc (INCLUDE f) = unwords ["$INCLUDE", f] ddesc (AbsDomain domain) = domain ddesc (RelDomain domain) = domain diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index 27f81f62..c5a4efa9 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -133,7 +133,7 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup -- TODO enable dnssec options. -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; setup = combineProperties ("dns primary for " ++ domain ++ " (signed)") - [ setupPrimary zonefile signedZoneFile hosts domain soa rs' + [ setupPrimary zonefile signedZoneFile hosts domain soa rs , toProp (zoneSigned domain zonefile) ] `onChange` Service.reloaded "bind9" @@ -142,10 +142,6 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup `onChange` toProp (revert (zoneSigned domain zonefile)) `onChange` Service.reloaded "bind9" - -- Include the public keys into the zone file. - rs' = include PubKSK : include PubZSK : rs - include k = (RootDomain, INCLUDE (keyFn domain k)) - -- Put DNSSEC zone files in a different directory than is used for -- the regular ones. This allows 'primary' to be reverted and -- 'signedPrimary' enabled, without the reverted property stomping @@ -271,7 +267,6 @@ rField (MX _ _) = "MX" rField (NS _) = "NS" rField (TXT _) = "TXT" rField (SRV _ _ _ _) = "SRV" -rField (INCLUDE _) = "$INCLUDE" rValue :: Record -> String rValue (Address (IPv4 addr)) = addr @@ -285,7 +280,6 @@ rValue (SRV priority weight port target) = unwords , show port , dValue target ] -rValue (INCLUDE f) = f rValue (TXT s) = [q] ++ filter (/= q) s ++ [q] where q = '"' diff --git a/src/Propellor/Property/DnsSec.hs b/src/Propellor/Property/DnsSec.hs index e4a8cad9..f39fcb25 100644 --- a/src/Propellor/Property/DnsSec.hs +++ b/src/Propellor/Property/DnsSec.hs @@ -41,6 +41,7 @@ zoneSigned :: Domain -> FilePath -> RevertableProperty zoneSigned domain zonefile = RevertableProperty setup cleanup where setup = check needupdate (forceZoneSigned domain zonefile) + `requires` includePubKeys domain zonefile `requires` toProp (keysInstalled domain) cleanup = combineProperties ("removed signed zone for " ++ domain) @@ -65,6 +66,12 @@ zoneSigned domain zonefile = RevertableProperty setup cleanup t2 <- getModificationTime f return (t2 >= t1) +includePubKeys :: Domain -> FilePath -> Property +includePubKeys domain zonefile = File.containsLines zonefile $ + map mkinclude [PubKSK, PubZSK] + where + mkinclude k = "$INCLUDE " ++ keyFn domain k + forceZoneSigned :: Domain -> FilePath -> Property forceZoneSigned domain zonefile = property ("zone signed for " ++ domain) $ liftIO $ do salt <- take 16 <$> saltSha1 @@ -95,8 +102,11 @@ saltSha1 = readProcess "sh" -- | The file used for a given key. keyFn :: Domain -> DnsSecKey -> FilePath -keyFn domain k = "/etc/bind/propellor/dnssec" - "K" ++ domain ++ "." ++ show k ++ keyExt k +keyFn domain k = "/etc/bind/propellor/dnssec" concat + [ "K" ++ domain ++ "." + , if isZoneSigningKey k then "ZSK" else "KSK" + , keyExt k + ] -- | These are the extensions that dnssec-keygen looks for. keyExt :: DnsSecKey -> String diff --git a/src/Propellor/Types/Dns.hs b/src/Propellor/Types/Dns.hs index 2fbf51e5..5e9666d8 100644 --- a/src/Propellor/Types/Dns.hs +++ b/src/Propellor/Types/Dns.hs @@ -62,7 +62,6 @@ data Record | NS BindDomain | TXT String | SRV Word16 Word16 Word16 BindDomain - | INCLUDE FilePath deriving (Read, Show, Eq, Ord) getIPAddr :: Record -> Maybe IPAddr -- cgit v1.3-2-g0d8e From bb7b8e789104a77b12030df5fe508afbe0eac2a5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 14:20:22 -0400 Subject: add $INCLUDE of pubkeys before zone file is written, to avoid pogoing --- src/Propellor/Info.hs | 1 + src/Propellor/Property/Dns.hs | 22 ++++++++++++++++------ src/Propellor/Property/DnsSec.hs | 7 ------- src/Propellor/Types/Dns.hs | 1 + 4 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Info.hs b/src/Propellor/Info.hs index 0437f8ec..3af3fc15 100644 --- a/src/Propellor/Info.hs +++ b/src/Propellor/Info.hs @@ -64,6 +64,7 @@ addDNS r = pureInfoProperty (rdesc r) $ mempty { _dns = S.singleton r } rdesc (NS d) = unwords ["NS", ddesc d] rdesc (TXT s) = unwords ["TXT", s] rdesc (SRV x y z d) = unwords ["SRV", show x, show y, show z, ddesc d] + rdesc (INCLUDE f) = unwords ["$INCLUDE", f] ddesc (AbsDomain domain) = domain ddesc (RelDomain domain) = domain diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index c5a4efa9..e9c7c769 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -133,7 +133,7 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup -- TODO enable dnssec options. -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; setup = combineProperties ("dns primary for " ++ domain ++ " (signed)") - [ setupPrimary zonefile signedZoneFile hosts domain soa rs + [ setupPrimary zonefile signedZoneFile hosts domain soa rs' , toProp (zoneSigned domain zonefile) ] `onChange` Service.reloaded "bind9" @@ -142,6 +142,10 @@ signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup `onChange` toProp (revert (zoneSigned domain zonefile)) `onChange` Service.reloaded "bind9" + -- Include the public keys into the zone file. + rs' = include PubKSK : include PubZSK : rs + include k = (RootDomain, INCLUDE (keyFn domain k)) + -- Put DNSSEC zone files in a different directory than is used for -- the regular ones. This allows 'primary' to be reverted and -- 'signedPrimary' enabled, without the reverted property stomping @@ -267,6 +271,7 @@ rField (MX _ _) = "MX" rField (NS _) = "NS" rField (TXT _) = "TXT" rField (SRV _ _ _ _) = "SRV" +rField (INCLUDE _) = "$INCLUDE" rValue :: Record -> String rValue (Address (IPv4 addr)) = addr @@ -280,6 +285,7 @@ rValue (SRV priority weight port target) = unwords , show port , dValue target ] +rValue (INCLUDE f) = f rValue (TXT s) = [q] ++ filter (/= q) s ++ [q] where q = '"' @@ -345,12 +351,16 @@ genZoneFile (Zone zdomain soa rs) = unlines $ header = com $ "BIND zone file for " ++ zdomain ++ ". Generated by propellor, do not edit." genRecord :: Domain -> (BindDomain, Record) -> String +genRecord _ (_, record@(INCLUDE _)) = intercalate "\t" + [ rField record + , rValue record + ] genRecord zdomain (domain, record) = intercalate "\t" - [ domainHost zdomain domain - , "IN" - , rField record - , rValue record - ] + [ domainHost zdomain domain + , "IN" + , rField record + , rValue record + ] genSOA :: SOA -> [String] genSOA soa = diff --git a/src/Propellor/Property/DnsSec.hs b/src/Propellor/Property/DnsSec.hs index 37eea09c..b7557006 100644 --- a/src/Propellor/Property/DnsSec.hs +++ b/src/Propellor/Property/DnsSec.hs @@ -41,7 +41,6 @@ zoneSigned :: Domain -> FilePath -> RevertableProperty zoneSigned domain zonefile = RevertableProperty setup cleanup where setup = check needupdate (forceZoneSigned domain zonefile) - `requires` includePubKeys domain zonefile `requires` toProp (keysInstalled domain) cleanup = combineProperties ("removed signed zone for " ++ domain) @@ -66,12 +65,6 @@ zoneSigned domain zonefile = RevertableProperty setup cleanup t2 <- getModificationTime f return (t2 >= t1) -includePubKeys :: Domain -> FilePath -> Property -includePubKeys domain zonefile = File.containsLines zonefile $ - map mkinclude [PubKSK, PubZSK] - where - mkinclude k = "$INCLUDE " ++ keyFn domain k - forceZoneSigned :: Domain -> FilePath -> Property forceZoneSigned domain zonefile = property ("zone signed for " ++ domain) $ liftIO $ do salt <- take 16 <$> saltSha1 diff --git a/src/Propellor/Types/Dns.hs b/src/Propellor/Types/Dns.hs index 5e9666d8..2fbf51e5 100644 --- a/src/Propellor/Types/Dns.hs +++ b/src/Propellor/Types/Dns.hs @@ -62,6 +62,7 @@ data Record | NS BindDomain | TXT String | SRV Word16 Word16 Word16 BindDomain + | INCLUDE FilePath deriving (Read, Show, Eq, Ord) getIPAddr :: Record -> Maybe IPAddr -- cgit v1.3-2-g0d8e From ad984e74e4c85f0305d9ce8255ac8909038be82d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 15:00:40 -0400 Subject: propellor spin --- config-joey.hs | 22 ++++++---------------- src/Propellor/Property/Dns.hs | 5 ++--- 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/config-joey.hs b/config-joey.hs index 73674ea6..8cfb9250 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -253,10 +253,10 @@ diatom = standardSystem "diatom.kitenet.net" (Stable "wheezy") "amd64" & JoeySites.oldUseNetServer hosts & alias "ns2.kitenet.net" - & myDnsPrimary "kitenet.net" [] - & myDnsPrimary' "joeyh.name" [] - & myDnsPrimary "ikiwiki.info" [] - & myDnsPrimary "olduse.net" + & myDnsPrimary False "kitenet.net" [] + & myDnsPrimary True "joeyh.name" [] + & myDnsPrimary False "ikiwiki.info" [] + & myDnsPrimary False "olduse.net" [ (RelDomain "article", CNAME $ AbsDomain "virgil.koldfront.dk") ] @@ -433,18 +433,8 @@ branchableSecondary = Dns.secondaryFor ["branchable.com"] hosts "branchable.com" -- Currently using diatom (ns2) as primary with secondaries -- elephant (ns3) and gandi. -- kite handles all mail. -myDnsPrimary :: Domain -> [(BindDomain, Record)] -> RevertableProperty -myDnsPrimary domain extras = Dns.primary hosts domain - (Dns.mkSOA "ns2.kitenet.net" 100) $ - [ (RootDomain, NS $ AbsDomain "ns2.kitenet.net") - , (RootDomain, NS $ AbsDomain "ns3.kitenet.net") - , (RootDomain, NS $ AbsDomain "ns6.gandi.net") - , (RootDomain, MX 0 $ AbsDomain "kitenet.net") - -- SPF only allows IP address of kitenet.net to send mail. - , (RootDomain, TXT "v=spf1 a:kitenet.net -all") - ] ++ extras -myDnsPrimary' :: Domain -> [(BindDomain, Record)] -> RevertableProperty -myDnsPrimary' domain extras = Dns.signedPrimary Daily hosts domain +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") , (RootDomain, NS $ AbsDomain "ns3.kitenet.net") diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index e9c7c769..b5c97d35 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -126,15 +126,14 @@ cleanupPrimary zonefile domain = check (doesFileExist zonefile) $ -- -- The 'Recurrance' controls how frequently the signature -- should be regenerated, using a new random salt, to prevent --- zone walking attacks. `Daily` is a reasonable choice. +-- zone walking attacks. `Weekly Nothing` is a reasonable choice. signedPrimary :: Recurrance -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup where - -- TODO enable dnssec options. - -- dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; setup = combineProperties ("dns primary for " ++ domain ++ " (signed)") [ setupPrimary zonefile signedZoneFile hosts domain soa rs' , toProp (zoneSigned domain zonefile) + , forceZoneSigned domain zonefile `period` recurrance ] `onChange` Service.reloaded "bind9" -- cgit v1.3-2-g0d8e From 0f41071cb5b2b41b7128b38ff33779c7b9e68cbd Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Jan 2015 15:22:22 -0400 Subject: transition docs --- src/Propellor/Property/Dns.hs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/Propellor/Property/Dns.hs') diff --git a/src/Propellor/Property/Dns.hs b/src/Propellor/Property/Dns.hs index b5c97d35..581a9bfe 100644 --- a/src/Propellor/Property/Dns.hs +++ b/src/Propellor/Property/Dns.hs @@ -127,6 +127,14 @@ cleanupPrimary zonefile domain = check (doesFileExist zonefile) $ -- The 'Recurrance' controls how frequently the signature -- should be regenerated, using a new random salt, to prevent -- zone walking attacks. `Weekly Nothing` is a reasonable choice. +-- +-- To transition from 'primary' to 'signedPrimary', you can revert +-- the 'primary' property, and add this property. +-- +-- Note that DNSSEC zone files use a serial number based on the unix epoch. +-- This is different from the serial number used by 'primary', so if you +-- want to later disable DNSSEC you will need to adjust the serial number +-- passed to mkSOA to ensure it is larger. signedPrimary :: Recurrance -> [Host] -> Domain -> SOA -> [(BindDomain, Record)] -> RevertableProperty signedPrimary recurrance hosts domain soa rs = RevertableProperty setup cleanup where -- cgit v1.3-2-g0d8e