summaryrefslogtreecommitdiff
path: root/src/Propellor/Types/PrivData.hs
blob: ab3e108ae0f5feea6e1f04ef302066419be8e047 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
module Propellor.Types.PrivData where

import Propellor.Types.OS

-- | Note that removing or changing field names will break the
-- serialized privdata files, so don't do that!
-- It's fine to add new fields.
data PrivDataField
	= DockerAuthentication
	| SshPubKey SshKeyType UserName
	| SshPrivKey SshKeyType UserName
	| SshAuthorizedKeys UserName
	| Password UserName
	| CryptPassword UserName
	| PrivFile FilePath
	| GpgKey
	deriving (Read, Show, Ord, Eq)

-- | Explains how the user can generate a particular PrivDataField.
howtoMkPrivDataField :: PrivDataField -> String
howtoMkPrivDataField fld = case fld of
	DockerAuthentication -> "/root/.dockercfg" `genbycmd` "docker login"
	SshPubKey keytype _ -> forexample $
		"sshkey.pub" `genbycmd` keygen keytype
	SshPrivKey keytype _ -> forexample $
		"sshkey" `genbycmd` keygen keytype
	SshAuthorizedKeys _ -> forexample "~/.ssh/id_rsa.pub"
	Password username -> "a password for " ++ username
	CryptPassword _ -> "a crypt(3)ed password, which can be generated by, for example: perl -e 'print crypt(shift, q{$6$}.shift)' 'somepassword' 'somesalt'"
	PrivFile f -> "file contents for " ++ f
	GpgKey -> "Either a gpg public key, exported with gpg --export -a, or a gpg private key, exported with gpg --export-secret-key -a"
  where
	genbycmd f cmd = f ++ " generated by running `" ++ cmd ++ "`"
	keygen keytype = "ssh-keygen -t " ++ sshKeyTypeParam keytype ++ " -f sshkey"
	forexample s = "for example, " ++ s

-- | A context in which a PrivDataField is used.
--
-- Often this will be a domain name. For example, 
-- Context "www.example.com" could be used for the SSL cert
-- for the web server serving that domain. Multiple hosts might
-- use that privdata.
--
-- This appears in serlialized privdata files.
newtype Context = Context String
	deriving (Read, Show, Ord, Eq)

-- | A context that varies depending on the HostName where it's used.
newtype HostContext = HostContext { mkHostContext :: HostName -> Context }

instance Show HostContext where
	show hc = show $ mkHostContext hc "<hostname>"

instance Ord HostContext where
	a <= b = show a <= show b

instance Eq HostContext where
	a == b = show a == show b

-- | Class of things that can be used as a Context.
class IsContext c where
	asContext :: HostName -> c -> Context
	asHostContext :: c -> HostContext

instance IsContext HostContext where
	asContext = flip mkHostContext
	asHostContext = id

instance IsContext Context where
	asContext _ c = c
	asHostContext = HostContext . const

-- | Use when a PrivDataField is not dependent on any paricular context.
anyContext :: Context
anyContext = Context "any"

-- | Makes a HostContext that consists just of the hostname.
hostContext :: HostContext
hostContext = HostContext Context

type PrivData = String

data SshKeyType = SshRsa | SshDsa | SshEcdsa | SshEd25519
	deriving (Read, Show, Ord, Eq)

-- | Parameter that would be passed to ssh-keygen to generate key of this type
sshKeyTypeParam :: SshKeyType -> String
sshKeyTypeParam SshRsa = "RSA"
sshKeyTypeParam SshDsa = "DSA"
sshKeyTypeParam SshEcdsa = "ECDSA"
sshKeyTypeParam SshEd25519 = "ED25519"