summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Propellor/Property/Apache.hs21
-rw-r--r--src/Propellor/Property/LetsEncrypt.hs51
2 files changed, 28 insertions, 44 deletions
diff --git a/src/Propellor/Property/Apache.hs b/src/Propellor/Property/Apache.hs
index c2c32a3b..d0bcadfa 100644
--- a/src/Propellor/Property/Apache.hs
+++ b/src/Propellor/Property/Apache.hs
@@ -161,12 +161,12 @@ httpsVirtualHost domain docroot letos = httpsVirtualHost' domain docroot letos [
-- | Like `httpsVirtualHost` but with additional config lines added.
httpsVirtualHost' :: Domain -> WebRoot -> LetsEncrypt.AgreeTOS -> [ConfigLine] -> Property NoInfo
-httpsVirtualHost' domain docroot letos addedcfg = setup
+httpsVirtualHost' domain docroot letos addedcfg = setuphttp
`requires` modEnabled "rewrite"
`requires` modEnabled "ssl"
- `before` LetsEncrypt.letsEncrypt letos domain docroot certinstaller
+ `before` setuphttps
where
- setup = siteEnabled' domain $
+ setuphttp = siteEnabled' domain $
-- The sslconffile is only created after letsencrypt gets
-- the cert. The "*" is needed to make apache not error
-- when the file doesn't exist.
@@ -179,22 +179,21 @@ httpsVirtualHost' domain docroot letos addedcfg = setup
-- Everything else redirects to https
, "RewriteRule ^/(.*) https://" ++ domain ++ "/$1 [L,R,NE]"
]
- certinstaller :: LetsEncrypt.CertInstaller
- certinstaller newcert _domain certfile privkeyfile chainfile _fullchainfile =
- combineProperties (domain ++ " ssl cert installed")
+ setuphttps = LetsEncrypt.letsEncrypt letos domain docroot
+ `onChange` combineProperties (domain ++ " ssl cert installed")
[ File.dirExists (takeDirectory cf)
, File.hasContent cf sslvhost
`onChange` reloaded
- -- always reload when the cert has changed
- , check (return newcert :: IO Bool) reloaded
+ -- always reload since the cert has changed
+ , reloaded
]
where
cf = sslconffile "letsencrypt"
sslvhost = vhost (Port 443)
[ "SSLEngine on"
- , "SSLCertificateFile " ++ certfile
- , "SSLCertificateKeyFile " ++ privkeyfile
- , "SSLCertificateChainFile " ++ chainfile
+ , "SSLCertificateFile " ++ LetsEncrypt.certFile domain
+ , "SSLCertificateKeyFile " ++ LetsEncrypt.privKeyFile domain
+ , "SSLCertificateChainFile " ++ LetsEncrypt.chainFile domain
]
sslconffile s = "/etc/apache2/sites-available/ssl/" ++ domain ++ "/" ++ s ++ ".conf"
vhost (Port p) ls =
diff --git a/src/Propellor/Property/LetsEncrypt.hs b/src/Propellor/Property/LetsEncrypt.hs
index 2df290be..d0dbc4e7 100644
--- a/src/Propellor/Property/LetsEncrypt.hs
+++ b/src/Propellor/Property/LetsEncrypt.hs
@@ -23,22 +23,29 @@ type WebRoot = FilePath
--
-- This should work with any web server, as long as letsencrypt can
-- write its temp files to the web root. The letsencrypt client does
--- not modify the web server's configuration in any way; instead the
--- `CertInstaller` is used once the client has successfully obtained the
--- certificate.
+-- not modify the web server's configuration in any way; this only obtains
+-- the certificate it does not make the web server use it.
--
-- This also handles renewing the certificate.
-- For renewel to work well, propellor needs to be
-- run periodically (at least a couple times per month).
--
--- See `Propellor.Property.Apache.httpsVirtualHost` for a property built using this.
-letsEncrypt :: AgreeTOS -> Domain -> WebRoot -> CertInstaller -> Property NoInfo
+-- This property returns `MadeChange` when the certificate is initially
+-- obtained, and when it's renewed. So, it can be combined with a property
+-- to make the webserver (or other server) use the certificate:
+--
+-- > letsEncrypt (AgreeTOS (Just "me@example.com")) "example.com" "/var/www"
+-- > `onChange` Apache.reload
+--
+-- See `Propellor.Property.Apache.httpsVirtualHost` for a simpler way to
+-- use letsencrypt, that is built on top of this.
+letsEncrypt :: AgreeTOS -> Domain -> WebRoot -> Property NoInfo
letsEncrypt tos domain = letsEncrypt' tos domain []
-- | Like `letsEncrypt`, but the certificate can be obtained for multiple
-- domains.
-letsEncrypt' :: AgreeTOS -> Domain -> [Domain] -> WebRoot -> CertInstaller -> Property NoInfo
-letsEncrypt' (AgreeTOS memail) domain domains webroot certinstaller =
+letsEncrypt' :: AgreeTOS -> Domain -> [Domain] -> WebRoot -> Property NoInfo
+letsEncrypt' (AgreeTOS memail) domain domains webroot =
prop `requires` installed
where
prop = property desc $ do
@@ -48,8 +55,9 @@ letsEncrypt' (AgreeTOS memail) domain domains webroot certinstaller =
if ok
then do
endstats <- liftIO getstats
- ensureProperty $
- certsinstalled (startstats /= endstats)
+ if startstats /= endstats
+ then return MadeChange
+ else return NoChange
else do
liftIO $ hPutStr stderr transcript
return FailedChange
@@ -78,31 +86,8 @@ letsEncrypt' (AgreeTOS memail) domain domains webroot certinstaller =
statfile f = catchMaybeIO $ do
s <- getFileStatus f
return (fileID s, deviceID s, fileMode s, fileSize s, modificationTime s)
-
- certsinstalled newcert = propertyList ("certs installed") $
- flip map alldomains $ \d -> certinstaller
- newcert d
- (certFile d)
- (privKeyFile d)
- (chainFile d)
- (fullChainFile d)
-
--- | A property that installs a certificate, once letsencrypt obtains it.
---
--- For example, it could configure the web server to use the certificate
--- files, and restart the web server.
---
--- The Bool is True when a new cerficate was just obtained.
--- But, this is also run when the certificate has not changed, so that
--- any changes to the property will take effect.
-type CertInstaller = Bool -> Domain -> CertFile -> PrivKeyFile -> ChainFile -> FullChainFile -> Property NoInfo
-
--- | Locations of certificate files generated by lets encrypt.
-type CertFile = FilePath
-type PrivKeyFile = FilePath
-type ChainFile = FilePath
-type FullChainFile = FilePath
+-- | The cerificate files that letsencrypt will make available for a domain.
liveCertDir :: Domain -> FilePath
liveCertDir d = "/etc/letsencrypt/live" </> d