diff options
Diffstat (limited to 'app/controllers/ca.go')
-rw-r--r-- | app/controllers/ca.go | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/app/controllers/ca.go b/app/controllers/ca.go index 632db50..c04dcd8 100644 --- a/app/controllers/ca.go +++ b/app/controllers/ca.go | |||
@@ -11,9 +11,24 @@ import ( | |||
11 | "code.crute.us/mcrute/ssh-proxy/app/middleware" | 11 | "code.crute.us/mcrute/ssh-proxy/app/middleware" |
12 | "code.crute.us/mcrute/ssh-proxy/app/models" | 12 | "code.crute.us/mcrute/ssh-proxy/app/models" |
13 | "github.com/labstack/echo/v4" | 13 | "github.com/labstack/echo/v4" |
14 | "github.com/prometheus/client_golang/prometheus" | ||
15 | "github.com/prometheus/client_golang/prometheus/promauto" | ||
14 | "golang.org/x/crypto/ssh" | 16 | "golang.org/x/crypto/ssh" |
15 | ) | 17 | ) |
16 | 18 | ||
19 | var ( | ||
20 | caError = promauto.NewCounterVec(prometheus.CounterOpts{ | ||
21 | Namespace: "ssh_proxy", | ||
22 | Name: "ssh_ca_error", | ||
23 | Help: "Total number of errors during SSH CA operation", | ||
24 | }, []string{"type"}) | ||
25 | caSuccess = promauto.NewCounter(prometheus.CounterOpts{ | ||
26 | Namespace: "ssh_proxy", | ||
27 | Name: "ssh_ca_success", | ||
28 | Help: "Total number of successful CA operations", | ||
29 | }) | ||
30 | ) | ||
31 | |||
17 | type CASecret struct { | 32 | type CASecret struct { |
18 | Key string `mapstructure:"key"` | 33 | Key string `mapstructure:"key"` |
19 | } | 34 | } |
@@ -57,24 +72,29 @@ func (h *CAHandler) authorizeRequest(c echo.Context, certRequest *ssh.Certificat | |||
57 | } | 72 | } |
58 | 73 | ||
59 | if user.Username != certRequest.ValidPrincipals[0] { | 74 | if user.Username != certRequest.ValidPrincipals[0] { |
75 | caError.With(prometheus.Labels{"type": "user_request_mismatch"}).Inc() | ||
60 | return fmt.Errorf("Authenticated username and cert username must match") | 76 | return fmt.Errorf("Authenticated username and cert username must match") |
61 | } | 77 | } |
62 | 78 | ||
63 | if !session.HasScope("ca:issue") { | 79 | if !session.HasScope("ca:issue") { |
80 | caError.With(prometheus.Labels{"type": "missing_oauth_scope"}).Inc() | ||
64 | return fmt.Errorf("Authorized session does not have scope ca:issue") | 81 | return fmt.Errorf("Authorized session does not have scope ca:issue") |
65 | } | 82 | } |
66 | 83 | ||
67 | if certRequest.Extensions == nil { | 84 | if certRequest.Extensions == nil { |
85 | caError.With(prometheus.Labels{"type": "no_extensions"}).Inc() | ||
68 | return fmt.Errorf("Cert request extensions are empty") | 86 | return fmt.Errorf("Cert request extensions are empty") |
69 | } | 87 | } |
70 | 88 | ||
71 | hostLine, ok := certRequest.Extensions["allowed-hosts"] | 89 | hostLine, ok := certRequest.Extensions["allowed-hosts"] |
72 | if !ok { | 90 | if !ok { |
91 | caError.With(prometheus.Labels{"type": "no_allowed_hosts"}).Inc() | ||
73 | return fmt.Errorf("Cert request allowed-hosts is blank") | 92 | return fmt.Errorf("Cert request allowed-hosts is blank") |
74 | } | 93 | } |
75 | 94 | ||
76 | for _, host := range strings.Split(hostLine, ",") { | 95 | for _, host := range strings.Split(hostLine, ",") { |
77 | if !user.AuthorizedForHost(host) { | 96 | if !user.AuthorizedForHost(host) { |
97 | caError.With(prometheus.Labels{"type": "user_no_auth_host"}).Inc() | ||
78 | return fmt.Errorf("User %s is not authorized for host %s", session.UserId, host) | 98 | return fmt.Errorf("User %s is not authorized for host %s", session.UserId, host) |
79 | } | 99 | } |
80 | } | 100 | } |
@@ -168,5 +188,7 @@ func (h *CAHandler) HandleIssue(c echo.Context) error { | |||
168 | }) | 188 | }) |
169 | } | 189 | } |
170 | 190 | ||
191 | caSuccess.Inc() | ||
192 | |||
171 | return c.Blob(http.StatusOK, "application/x-ssh-certificate", ssh.MarshalAuthorizedKey(certToIssue)) | 193 | return c.Blob(http.StatusOK, "application/x-ssh-certificate", ssh.MarshalAuthorizedKey(certToIssue)) |
172 | } | 194 | } |