8
8
"io/ioutil"
9
9
"net/http"
10
10
"os"
11
+ "regexp"
11
12
"strings"
12
13
"sync"
13
14
"sync/atomic"
@@ -18,30 +19,108 @@ type member struct {
18
19
Keys []string
19
20
}
20
21
21
- func main () {
22
- ms := getMembers ()
23
- ms = getKeys (ms )
24
- printReport (ms )
22
+ type keyTable struct {
23
+ keyDsaSize uint32
24
+ keyEcdsaSize uint32
25
+ keyEd25519Size uint32
26
+ keyRsaSize uint32
27
+ keyStrongRsaSize uint32
28
+ keyWeakRsaSize uint32
29
+ userDsaSize uint32
30
+ userEcdsaSize uint32
31
+ userEd25519Size uint32
32
+ userRsaSize uint32
33
+ userWithKeySize uint32
34
+ userWithoutKeySize uint32
35
+ userWithMultipleKeySize uint32
36
+ keySize uint32
37
+ strongKeySize uint32
38
+ weakKeySize uint32
39
+ userSize uint32
40
+ userWithStrongKeySize uint32
41
+ userWithWeakKeySize uint32
42
+ userWithWeakKey []member
43
+ }
44
+
45
+ func printReport (kt keyTable ) {
46
+ withKey := [][]string {
47
+ {"users with keys" ,
48
+ "DSA" ,
49
+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyDsaSize , float32 (kt .keyDsaSize )/ float32 (kt .keySize )* 100 ),
50
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userDsaSize , float32 (kt .userDsaSize )/ float32 (kt .userSize )* 100 )},
51
+ {"" ,
52
+ "ECDSA" ,
53
+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyEcdsaSize , float32 (kt .keyEcdsaSize )/ float32 (kt .keySize )* 100 ),
54
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userEcdsaSize , float32 (kt .userEcdsaSize )/ float32 (kt .userSize )* 100 )},
55
+ {"" ,
56
+ "Ed25519" ,
57
+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyEd25519Size , float32 (kt .keyEd25519Size )/ float32 (kt .keySize )* 100 ),
58
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userEd25519Size , float32 (kt .userEd25519Size )/ float32 (kt .userSize )* 100 )},
59
+ {"" ,
60
+ "RSA" ,
61
+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyRsaSize , float32 (kt .keyRsaSize )/ float32 (kt .keySize )* 100 ),
62
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userRsaSize , float32 (kt .userRsaSize )/ float32 (kt .userSize )* 100 )},
63
+ }
64
+
65
+ withoutKey := [][]string {
66
+ {"users without keys" ,
67
+ "" ,
68
+ "" ,
69
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithoutKeySize , float32 (kt .userWithoutKeySize )/ float32 (kt .userSize )* 100 )},
70
+ }
71
+
72
+ withMultipleKey := [][]string {{"users with multiple keys" ,
73
+ "" ,
74
+ "" ,
75
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithMultipleKeySize , float32 (kt .userWithMultipleKeySize )/ float32 (kt .userSize )* 100 )},
76
+ }
77
+
78
+ strongKey := [][]string {
79
+ {"users with strong keys" ,
80
+ "" ,
81
+ fmt .Sprintf ("%d (%.2f%%)" , kt .strongKeySize , float32 (kt .strongKeySize )/ float32 (kt .keySize )* 100 ),
82
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithStrongKeySize , float32 (kt .userWithStrongKeySize )/ float32 (kt .userWithKeySize )* 100 )},
83
+ }
84
+
85
+ weakKey := [][]string {
86
+ {"users with weak keys" ,
87
+ "" ,
88
+ fmt .Sprintf ("%d (%.2f%%)" , kt .weakKeySize , float32 (kt .weakKeySize )/ float32 (kt .keySize )* 100 ),
89
+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithWeakKeySize , float32 (kt .userWithWeakKeySize )/ float32 (kt .userWithKeySize )* 100 )},
90
+ }
91
+
92
+ t := tablewriter .NewWriter (os .Stdout )
93
+ t .SetHeader ([]string {"description" , "key type" , "# of keys" , "# of users" })
94
+ t .SetHeaderColor (tablewriter.Colors {tablewriter .FgCyanColor },
95
+ tablewriter.Colors {tablewriter .FgCyanColor },
96
+ tablewriter.Colors {tablewriter .FgCyanColor },
97
+ tablewriter.Colors {tablewriter .FgCyanColor })
98
+ t .SetFooter ([]string {"" , "total" , fmt .Sprintf ("%d" , kt .keySize ), fmt .Sprintf ("%d" , kt .userSize )})
99
+ t .SetFooterColor (tablewriter.Colors {tablewriter .FgCyanColor },
100
+ tablewriter.Colors {tablewriter .FgCyanColor },
101
+ tablewriter.Colors {tablewriter .FgCyanColor },
102
+ tablewriter.Colors {tablewriter .FgCyanColor })
103
+ t .SetRowLine (true )
104
+ t .AppendBulk (withKey )
105
+ t .AppendBulk (withoutKey )
106
+ t .AppendBulk (withMultipleKey )
107
+ t .AppendBulk (strongKey )
108
+ t .AppendBulk (weakKey )
109
+ t .Render ()
110
+
111
+ if len (kt .userWithWeakKey ) > 0 {
112
+ zap .S ().Info ("users with weak keys:" )
113
+ for _ , m := range kt .userWithWeakKey {
114
+ zap .S ().Infof ("%s" , m .Login )
115
+ }
116
+ }
25
117
}
26
118
27
- func printReport (ms []member ) {
119
+ func generateKeyTable (ms []member ) keyTable {
28
120
var wg sync.WaitGroup
29
121
30
- var (
31
- keyDsaSize uint32
32
- keyEddsaSize uint32
33
- keyEd25519Size uint32
34
- keyRsaSize uint32
35
- userDsaSize uint32
36
- userEddsaSize uint32
37
- userEd25519Size uint32
38
- userRsaSize uint32
39
- userWithKeySize uint32
40
- userWithoutKeySize uint32
41
- userWithMultipleKeySize uint32
42
- totalKeySize uint32
43
- totalUserSize = len (ms )
44
- )
122
+ var kt keyTable
123
+ kt .userSize = uint32 (len (ms ))
45
124
46
125
for _ , m := range ms {
47
126
wg .Add (1 )
@@ -51,44 +130,68 @@ func printReport(ms []member) {
51
130
defer wg .Done ()
52
131
53
132
var (
54
- hasDsa bool
55
- hasRsa bool
56
- hasEddsa bool
57
- hasEd25519 bool
133
+ hasDsa bool
134
+ hasEcdsa bool
135
+ hasEd25519 bool
136
+ hasRsa bool
137
+ userHasStrongRsa bool
58
138
)
59
139
60
140
for _ , key := range m .Keys {
61
- atomic .AddUint32 (& totalKeySize , 1 )
141
+ atomic .AddUint32 (& kt . keySize , 1 )
62
142
63
143
switch {
64
144
case strings .Contains (key , "ssh-dsa" ):
65
- atomic .AddUint32 (& keyDsaSize , 1 )
66
145
hasDsa = true
67
- case strings .Contains (key , "ssh-rsa" ):
68
- atomic .AddUint32 (& keyRsaSize , 1 )
69
- hasRsa = true
146
+ atomic .AddUint32 (& kt .keyDsaSize , 1 )
147
+ atomic .AddUint32 (& kt .weakKeySize , 1 )
70
148
case strings .Contains (key , "ssh-eddsa" ):
71
- atomic .AddUint32 (& keyEddsaSize , 1 )
72
- hasEddsa = true
149
+ hasEcdsa = true
150
+ atomic .AddUint32 (& kt .keyEcdsaSize , 1 )
151
+ atomic .AddUint32 (& kt .weakKeySize , 1 )
73
152
case strings .Contains (key , "ssh-ed25519" ):
74
- atomic .AddUint32 (& keyEd25519Size , 1 )
75
153
hasEd25519 = true
154
+ atomic .AddUint32 (& kt .keyEd25519Size , 1 )
155
+ atomic .AddUint32 (& kt .strongKeySize , 1 )
156
+ case strings .Contains (key , "ssh-rsa" ):
157
+ hasRsa = true
158
+ atomic .AddUint32 (& kt .keyRsaSize , 1 )
159
+ if isRsaStrong (key ) {
160
+ userHasStrongRsa = true
161
+ atomic .AddUint32 (& kt .keyStrongRsaSize , 1 )
162
+ atomic .AddUint32 (& kt .strongKeySize , 1 )
163
+ } else {
164
+ userHasStrongRsa = false
165
+ atomic .AddUint32 (& kt .keyWeakRsaSize , 1 )
166
+ atomic .AddUint32 (& kt .weakKeySize , 1 )
167
+ }
76
168
}
77
169
}
78
170
79
171
switch {
80
172
case hasDsa :
81
- atomic .AddUint32 (& userDsaSize , 1 )
82
- case hasRsa :
83
- atomic .AddUint32 (& userRsaSize , 1 )
84
- case hasEddsa :
85
- atomic .AddUint32 (& userEddsaSize , 1 )
173
+ atomic .AddUint32 (& kt .userDsaSize , 1 )
174
+ atomic .AddUint32 (& kt .userWithWeakKeySize , 1 )
175
+ kt .userWithWeakKey = append (kt .userWithWeakKey , m )
176
+ case hasEcdsa :
177
+ atomic .AddUint32 (& kt .userEcdsaSize , 1 )
178
+ atomic .AddUint32 (& kt .userWithWeakKeySize , 1 )
179
+ kt .userWithWeakKey = append (kt .userWithWeakKey , m )
86
180
case hasEd25519 :
87
- atomic .AddUint32 (& userEd25519Size , 1 )
181
+ atomic .AddUint32 (& kt .userEd25519Size , 1 )
182
+ atomic .AddUint32 (& kt .userWithStrongKeySize , 1 )
183
+ case hasRsa :
184
+ atomic .AddUint32 (& kt .userRsaSize , 1 )
185
+ if userHasStrongRsa {
186
+ atomic .AddUint32 (& kt .userWithStrongKeySize , 1 )
187
+ } else {
188
+ atomic .AddUint32 (& kt .userWithWeakKeySize , 1 )
189
+ kt .userWithWeakKey = append (kt .userWithWeakKey , m )
190
+ }
88
191
}
89
192
90
193
if len (m .Keys ) == 0 {
91
- atomic .AddUint32 (& userWithoutKeySize , 1 )
194
+ atomic .AddUint32 (& kt . userWithoutKeySize , 1 )
92
195
if * showUsers == "without" || * showUsers == "all" {
93
196
zap .S ().Infow ("retrieved keys" ,
94
197
"user" , m .Login ,
@@ -98,7 +201,7 @@ func printReport(ms []member) {
98
201
}
99
202
100
203
if len (m .Keys ) > 0 {
101
- atomic .AddUint32 (& userWithKeySize , 1 )
204
+ atomic .AddUint32 (& kt . userWithKeySize , 1 )
102
205
if * showUsers == "with" || * showUsers == "all" {
103
206
zap .S ().Infow ("retrieved keys" ,
104
207
"user" , m .Login ,
@@ -108,7 +211,7 @@ func printReport(ms []member) {
108
211
}
109
212
110
213
if len (m .Keys ) > 1 {
111
- atomic .AddUint32 (& userWithMultipleKeySize , 1 )
214
+ atomic .AddUint32 (& kt . userWithMultipleKeySize , 1 )
112
215
if * showUsers == "multiple" || * showUsers == "all" {
113
216
zap .S ().Infow ("retrieved keys" ,
114
217
"user" , m .Login ,
@@ -120,47 +223,13 @@ func printReport(ms []member) {
120
223
}
121
224
wg .Wait ()
122
225
123
- withKey := [][]string {
124
- {"users with keys" , "DSA" ,
125
- fmt .Sprintf ("%d (%.2f%%)" , keyDsaSize , float32 (keyDsaSize )/ float32 (totalKeySize )* 100 ),
126
- fmt .Sprintf ("%d (%.2f%%)" , userDsaSize , float32 (userDsaSize )/ float32 (totalUserSize )* 100 )},
127
- {"" , "RSA" ,
128
- fmt .Sprintf ("%d (%.2f%%)" , keyRsaSize , float32 (keyRsaSize )/ float32 (totalKeySize )* 100 ),
129
- fmt .Sprintf ("%d (%.2f%%)" , userRsaSize , float32 (userRsaSize )/ float32 (totalUserSize )* 100 )},
130
- {"" , "ECDSA" ,
131
- fmt .Sprintf ("%d (%.2f%%)" , keyEddsaSize , float32 (keyEddsaSize )/ float32 (totalKeySize )* 100 ),
132
- fmt .Sprintf ("%d (%.2f%%)" , userEddsaSize , float32 (userEddsaSize )/ float32 (totalUserSize )* 100 )},
133
- {"" , "Ed25519" ,
134
- fmt .Sprintf ("%d (%.2f%%)" , keyEd25519Size , float32 (keyEd25519Size )/ float32 (totalKeySize )* 100 ),
135
- fmt .Sprintf ("%d (%.2f%%)" , userEd25519Size , float32 (userEd25519Size )/ float32 (totalUserSize )* 100 )},
136
- }
137
-
138
- withoutKey := [][]string {
139
- {"users without keys" , "" , "" , fmt .Sprintf ("%d (%.2f%%)" , userWithoutKeySize , float32 (userWithoutKeySize )/ float32 (totalUserSize )* 100 )},
140
- }
141
-
142
- withMultipleKey := [][]string {
143
- {"users with multiple keys" , "" , "" , fmt .Sprintf ("%d (%.2f%%)" , userWithMultipleKeySize , float32 (userWithMultipleKeySize )/ float32 (totalUserSize )* 100 )},
144
- }
226
+ return kt
227
+ }
145
228
146
- t := tablewriter .NewWriter (os .Stdout )
147
- t .SetHeader ([]string {"description" , "key type" , "# of keys" , "# of users" })
148
- t .SetHeaderColor (tablewriter.Colors {tablewriter .FgCyanColor },
149
- tablewriter.Colors {tablewriter .FgCyanColor },
150
- tablewriter.Colors {tablewriter .FgCyanColor },
151
- tablewriter.Colors {tablewriter .FgCyanColor },
152
- )
153
- t .SetFooter ([]string {"" , "total" , fmt .Sprintf ("%d" , totalKeySize ), fmt .Sprintf ("%d" , totalUserSize )})
154
- t .SetFooterColor (tablewriter.Colors {tablewriter .FgCyanColor },
155
- tablewriter.Colors {tablewriter .FgCyanColor },
156
- tablewriter.Colors {tablewriter .FgCyanColor },
157
- tablewriter.Colors {tablewriter .FgCyanColor },
158
- )
159
- t .SetRowLine (true )
160
- t .AppendBulk (withKey )
161
- t .AppendBulk (withoutKey )
162
- t .AppendBulk (withMultipleKey )
163
- t .Render ()
229
+ func isRsaStrong (key string ) bool {
230
+ r := regexp .MustCompile (`(ssh-rsa) (.*)` )
231
+ keyArray := r .FindStringSubmatch (key )
232
+ return len (keyArray [2 ]) >= 372
164
233
}
165
234
166
235
func getKeys (ms []member ) []member {
@@ -250,3 +319,7 @@ func getMembers() []member {
250
319
251
320
return members
252
321
}
322
+
323
+ func main () {
324
+ printReport (generateKeyTable (getKeys (getMembers ())))
325
+ }
0 commit comments