Add in most of the proxy flow (#326)
This commit is contained in:
1 parent
1822c47ef5
commit
23156afa11
31 files changed
+1372
-184
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
VERSION="1.14"
|
||||
VERSION="1.15.1"
|
||||
|
||||
[ -z "$GOROOT" ] && GOROOT="$HOME/.go"
|
||||
[ -z "$GOPATH" ] && GOPATH="$HOME/go"
|
||||
|
||||
@@ -10,6 +10,7 @@ import "time"
|
||||
// only ever be set at startup, but simply available to reference from anywhere.
|
||||
|
||||
const (
|
||||
TcpProxyV1 = "boundary-tcp-proxy-v1"
|
||||
TokenEncryptionVersion = "1"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/hashicorp/boundary
|
||||
|
||||
go 1.13
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/armon/go-metrics v0.3.4
|
||||
@@ -19,7 +19,7 @@ require (
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.0-beta.4.0.20200813083929-9bdca3d79b97
|
||||
github.com/hashicorp/dbassert v0.0.0-20200602142727-a6709b436ad6
|
||||
github.com/hashicorp/errwrap v1.0.0
|
||||
github.com/hashicorp/go-alpnmux v0.0.0-20200513011953-0293f5d23c31
|
||||
github.com/hashicorp/go-alpnmux v0.0.0-20200822022353-14527cfc58e5
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||
github.com/hashicorp/go-hclog v0.14.1
|
||||
github.com/hashicorp/go-kms-wrapping v0.5.14
|
||||
@@ -59,4 +59,5 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20200813001606-1ccf2a5ae4fd
|
||||
google.golang.org/grpc v1.31.0
|
||||
google.golang.org/protobuf v1.25.0
|
||||
nhooyr.io/websocket v1.8.6
|
||||
)
|
||||
@@ -117,7 +117,6 @@ github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
|
||||
github.com/armon/go-metrics v0.3.3 h1:a9F4rlj7EWWrbj7BYw8J8+x+ZZkJeqzNyRk8hdPF+ro=
|
||||
github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
github.com/armon/go-metrics v0.3.4 h1:Xqf+7f2Vhl9tsqDYmXhnXInUdcrtgpRNpIA15/uldSc=
|
||||
github.com/armon/go-metrics v0.3.4/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
@@ -149,7 +148,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
@@ -281,6 +279,10 @@ github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
@@ -365,6 +367,14 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
|
||||
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
|
||||
github.com/go-openapi/validate v0.19.10 h1:tG3SZ5DC5KF4cyt7nqLVcQXGj5A7mpaYkAcNPlDK+Yk=
|
||||
github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
@@ -403,6 +413,12 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
|
||||
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
|
||||
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
|
||||
@@ -499,11 +515,12 @@ github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
@@ -518,8 +535,8 @@ github.com/hashicorp/dbassert v0.0.0-20200602142727-a6709b436ad6 h1:Nejn3Kli0VXW
|
||||
github.com/hashicorp/dbassert v0.0.0-20200602142727-a6709b436ad6/go.mod h1:+B5eZq7vXqN4Gxkgjm4ub1bwG6OTcYzFL0r+bMvWorg=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-alpnmux v0.0.0-20200513011953-0293f5d23c31 h1:pxqI71/0R1WIASjQEJ9W9skCKYiREEkRoXFvHCZH1pg=
|
||||
github.com/hashicorp/go-alpnmux v0.0.0-20200513011953-0293f5d23c31/go.mod h1:KvpteZzIafT4tRAuQ9vVRBgZyqeVCS2B2177fNAyEZc=
|
||||
github.com/hashicorp/go-alpnmux v0.0.0-20200822022353-14527cfc58e5 h1:2YnwbJbobkTULUOhJ77seiSGqd7tD3V7zFXn7u5666k=
|
||||
github.com/hashicorp/go-alpnmux v0.0.0-20200822022353-14527cfc58e5/go.mod h1:KvpteZzIafT4tRAuQ9vVRBgZyqeVCS2B2177fNAyEZc=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
@@ -533,7 +550,6 @@ github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc=
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-kms-wrapping v0.5.12 h1:4zZCaLqOob5moaAmpS6ZtGZYm4yOcqvmt2lO+zNXHls=
|
||||
github.com/hashicorp/go-kms-wrapping v0.5.12/go.mod h1:yVIWtGOTh/cdGc++/NOlXLus0hJ19Lz4iFrpF6WsZh4=
|
||||
github.com/hashicorp/go-kms-wrapping v0.5.14 h1:XtNZYE9n4ypz9CnhQc/5Vd6ovGqbHO1lQ3IVPc2TV+w=
|
||||
github.com/hashicorp/go-kms-wrapping v0.5.14/go.mod h1:hKJ7tS+eMXOLxwFs7mYJtPRQtT/rGtwqE6awY3JATCw=
|
||||
@@ -547,7 +563,6 @@ github.com/hashicorp/go-plugin v1.2.0 h1:CUfYokW0EJNDcGecVrHZK//Cp1GFlHwoqtcUIEi
|
||||
github.com/hashicorp/go-plugin v1.2.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
@@ -581,7 +596,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||
github.com/hashicorp/shared-secure-libs v0.0.2 h1:+izKlB8vxpBK+K6zNmB4DZtDEl1a7fB8JmqdBNhnhjs=
|
||||
github.com/hashicorp/shared-secure-libs v0.0.2/go.mod h1:xhtA0FH6AYYFOy0sir7u0O0zzdLi7ofU6oWxy+gjnuc=
|
||||
github.com/hashicorp/vault/api v1.0.5-0.20200514164214-89b1987e38c2/go.mod h1:P8A7gn1a6j/7qQ4zOaWI6FC/Q9jQWEBRTOwZH33tC9o=
|
||||
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f h1:PYtnlUZzFSZxPcq7mYp5oC9N+BcJ8IKYf6/EG0GHM2Y=
|
||||
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE=
|
||||
github.com/hashicorp/vault/api v1.0.5-0.20200805123347-1ef507638af6 h1:ChHpobQse3kjVX7GmbpUFVqaMTf4lb1gcLrJltsUmS4=
|
||||
github.com/hashicorp/vault/api v1.0.5-0.20200805123347-1ef507638af6/go.mod h1:R3Umvhlxi2TN7Ex2hzOowyeNb+SfbVWI973N+ctaFMk=
|
||||
@@ -600,7 +614,6 @@ github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/golangsdk v0.0.0-20200304081349-45ec0797f2a4/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk=
|
||||
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/iancoleman/strcase v0.1.0 h1:Lar8rut26AXkJUmVOb2bRsFGv//+tJBeJLxXvpZpF1Q=
|
||||
github.com/iancoleman/strcase v0.1.0/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
@@ -693,7 +706,6 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -714,6 +726,7 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
|
||||
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
|
||||
@@ -736,6 +749,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@@ -915,7 +930,6 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI=
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
@@ -932,7 +946,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.11.1 h1:0ZISXCMRuCZcxF77aT1BXY5m74mX2vrGYl1dSwBI0Jo=
|
||||
@@ -943,7 +956,6 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
@@ -960,7 +972,6 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
@@ -1036,6 +1047,10 @@ github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9r
|
||||
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
@@ -1437,7 +1452,6 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200527211525-6c9e30c09db2 h1:KNluVV5ay+orsSPJ6XTpwJQ8qBhrBkOTmtBFGeDlBcY=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200527211525-6c9e30c09db2/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@@ -1519,6 +1533,8 @@ modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
|
||||
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
|
||||
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
|
||||
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
@@ -65,7 +65,7 @@ func tcpListenerFactory(l *configutil.Listener, logger hclog.Logger, ui cli.Ui)
|
||||
switch l.Purpose[0] {
|
||||
case "cluster":
|
||||
l.Address = "127.0.0.1:9201"
|
||||
case "worker-alpn-tls":
|
||||
case "proxy":
|
||||
l.Address = "127.0.0.1:9202"
|
||||
default:
|
||||
l.Address = "127.0.0.1:9200"
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/hostcatalogs"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/hosts"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/hostsets"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/proxy"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/roles"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/scopes"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/users"
|
||||
@@ -59,6 +60,11 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
SigUSR2Ch: MakeSigUSR2Ch(),
|
||||
}, nil
|
||||
},
|
||||
"proxy": func() (cli.Command, error) {
|
||||
return &proxy.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
}, nil
|
||||
},
|
||||
|
||||
"authenticate": func() (cli.Command, error) {
|
||||
return &authenticate.Command{
|
||||
|
||||
@@ -253,7 +253,7 @@ func (c *Command) Run(args []string) int {
|
||||
foundCluster = true
|
||||
case "api":
|
||||
foundAPI = true
|
||||
case "worker-alpn-tls":
|
||||
case "proxy":
|
||||
// Do nothing, in a dev mode we might see it here
|
||||
default:
|
||||
c.UI.Error(fmt.Sprintf("Unknown listener purpose %q", lnConfig.Purpose[0]))
|
||||
|
||||
@@ -235,7 +235,7 @@ func (c *Command) Run(args []string) int {
|
||||
c.Info["[Recovery] AEAD Key Bytes"] = devConfig.Controller.DevRecoveryKey
|
||||
|
||||
// Initialize the listeners
|
||||
if err := c.SetupListeners(c.UI, devConfig.SharedConfig, []string{"api", "cluster", "worker-alpn-tls"}); err != nil {
|
||||
if err := c.SetupListeners(c.UI, devConfig.SharedConfig, []string{"api", "cluster", "proxy"}); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
"nhooyr.io/websocket"
|
||||
)
|
||||
|
||||
var _ cli.Command = (*Command)(nil)
|
||||
var _ cli.CommandAutocomplete = (*Command)(nil)
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
|
||||
flagAuth string
|
||||
flagListenAddr string
|
||||
flagListenPort int
|
||||
flagVerbose bool
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
return "Launch the Boundary CLI in proxy mode"
|
||||
}
|
||||
|
||||
func (c *Command) Help() string {
|
||||
return base.WrapForHelpText([]string{
|
||||
"Usage: boundary proxy [options] [args]",
|
||||
"",
|
||||
" This command allows launching the Boundary CLI in proxy mode. In this mode, the CLI expects to take in an authorization string returned from a Boundary controller. The CLI will then create a connection to a Boundary worker and ready a listening port for a local connection.",
|
||||
"",
|
||||
" Example:",
|
||||
"",
|
||||
` $ boundary proxy -auth "UgxzX29mVEpwNUt6QlGiAQ..."`,
|
||||
"",
|
||||
" Please see the {{type}}s subcommand help for detailed usage information.",
|
||||
}) + c.Flags().Help()
|
||||
}
|
||||
|
||||
func (c *Command) Flags() *base.FlagSets {
|
||||
set := c.FlagSet(0)
|
||||
|
||||
f := set.NewFlagSet("Proxy Options")
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "auth",
|
||||
Target: &c.flagAuth,
|
||||
EnvVar: "BOUNDARY_PROXY_AUTH",
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: `The authorization string returned from the Boundary controller. If set to "-", the command will attempt to read in the authorization string from standard input.`,
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "listen-addr",
|
||||
Target: &c.flagListenAddr,
|
||||
EnvVar: "BOUNDARY_PROXY_LISTEN_ADDR",
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: `If set, the CLI will attempt to bind its listening address to the given value, which must be an IP address. If it cannot, the command will error. If not set, defaults to the most common IPv4 loopback address (127.0.0.1)."`,
|
||||
})
|
||||
|
||||
f.IntVar(&base.IntVar{
|
||||
Name: "listen-port",
|
||||
Target: &c.flagListenPort,
|
||||
EnvVar: "BOUNDARY_PROXY_LISTEN_PORT",
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: `If set, the CLI will attempt to bind its listening port to the given value. If it cannot, the command will error."`,
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "verbose",
|
||||
Target: &c.flagVerbose,
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: "Turns on some extra verbosity in the command output.",
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteArgs() complete.Predictor {
|
||||
return complete.PredictAnything
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteFlags() complete.Flags {
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if c.flagListenAddr == "" {
|
||||
c.flagListenAddr = "127.0.0.1"
|
||||
}
|
||||
listenAddr := net.ParseIP(c.flagListenAddr)
|
||||
if listenAddr == nil {
|
||||
c.UI.Error(fmt.Sprintf("Could not successfully parse listen address of %s", c.flagListenAddr))
|
||||
return 1
|
||||
}
|
||||
|
||||
if c.flagAuth == "-" {
|
||||
authBytes, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("No authorization string was provided and encountered the following error attempting to read it from stdin: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
if len(authBytes) == 0 {
|
||||
c.UI.Error("No authorization data read from stdin")
|
||||
return 1
|
||||
}
|
||||
c.flagAuth = string(authBytes)
|
||||
}
|
||||
|
||||
marshaled, err := base64.RawStdEncoding.DecodeString(c.flagAuth)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to decode authorization string: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
sessionInfo := new(services.ValidateSessionResponse)
|
||||
if err := proto.Unmarshal(marshaled, sessionInfo); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to proto-decode authorization string: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(sessionInfo.GetWorkerInfo()) == 0 {
|
||||
c.UI.Error("No workers found in authorization string")
|
||||
return 1
|
||||
}
|
||||
|
||||
parsedCert, err := x509.ParseCertificate(sessionInfo.Certificate)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to decode mTLS certificate: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(parsedCert.DNSNames) != 1 {
|
||||
c.UI.Error(fmt.Errorf("mTLS certificate has invalid parameters: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AddCert(parsedCert)
|
||||
|
||||
tlsConf := &tls.Config{
|
||||
Certificates: []tls.Certificate{
|
||||
{
|
||||
Certificate: [][]byte{sessionInfo.Certificate},
|
||||
PrivateKey: ed25519.PrivateKey(sessionInfo.PrivateKey),
|
||||
Leaf: parsedCert,
|
||||
},
|
||||
},
|
||||
RootCAs: certPool,
|
||||
ServerName: parsedCert.DNSNames[0],
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
|
||||
transport := cleanhttp.DefaultTransport()
|
||||
transport.DisableKeepAlives = false
|
||||
transport.TLSClientConfig = tlsConf
|
||||
|
||||
listener, err := net.ListenTCP("tcp", &net.TCPAddr{
|
||||
IP: listenAddr,
|
||||
Port: c.flagListenPort,
|
||||
})
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error starting listening port: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
c.UI.Info(fmt.Sprintf("%s", listener.Addr().String()))
|
||||
|
||||
workerAddr := sessionInfo.GetWorkerInfo()[0].GetAddress()
|
||||
|
||||
conn, resp, err := websocket.Dial(
|
||||
c.Context,
|
||||
fmt.Sprintf("wss://%s/v1/proxy", workerAddr),
|
||||
&websocket.DialOptions{
|
||||
HTTPClient: &http.Client{
|
||||
Transport: transport,
|
||||
},
|
||||
Subprotocols: []string{globals.TcpProxyV1},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
switch {
|
||||
case strings.Contains(err.Error(), "tls: internal error"):
|
||||
c.UI.Error("Session is unauthorized")
|
||||
case strings.Contains(err.Error(), "connect: connection refused"):
|
||||
c.UI.Error(fmt.Sprintf("Unable to connect to worker at %s", workerAddr))
|
||||
default:
|
||||
c.UI.Error(fmt.Errorf("Error dialing the worker: %w", err).Error())
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
c.UI.Error("Response from worker is nil")
|
||||
return 1
|
||||
}
|
||||
if resp.Header == nil {
|
||||
c.UI.Error("Response header is nil")
|
||||
return 1
|
||||
}
|
||||
negProto := resp.Header.Get("Sec-WebSocket-Protocol")
|
||||
if negProto != globals.TcpProxyV1 {
|
||||
c.UI.Error(fmt.Sprintf("Unexpected negotiated protocol: %s", negProto))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get a wrapped net.Conn so we can use io.Copy
|
||||
netConn := websocket.NetConn(c.Context, conn, websocket.MessageBinary)
|
||||
|
||||
// Allow closing the listener from Ctrl-C
|
||||
go func() {
|
||||
<-c.Context.Done()
|
||||
listener.Close()
|
||||
}()
|
||||
|
||||
listeningConn, err := listener.AcceptTCP()
|
||||
listener.Close()
|
||||
if err != nil {
|
||||
select {
|
||||
case <-c.Context.Done():
|
||||
return 0
|
||||
default:
|
||||
c.UI.Error(fmt.Errorf("Error accepting connection: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
connWg := new(sync.WaitGroup)
|
||||
connWg.Add(2)
|
||||
go func() {
|
||||
defer connWg.Done()
|
||||
_, err := io.Copy(netConn, listeningConn)
|
||||
if c.flagVerbose {
|
||||
c.UI.Info(fmt.Sprintf("copy from client to endpoint done, error: %v", err))
|
||||
}
|
||||
netConn.Close()
|
||||
listeningConn.Close()
|
||||
}()
|
||||
go func() {
|
||||
defer connWg.Done()
|
||||
_, err := io.Copy(listeningConn, netConn)
|
||||
if c.flagVerbose {
|
||||
c.UI.Info(fmt.Sprintf("copy from endpoint to client done, error: %v", err))
|
||||
}
|
||||
listeningConn.Close()
|
||||
netConn.Close()
|
||||
}()
|
||||
connWg.Wait()
|
||||
return 0
|
||||
}
|
||||
@@ -188,7 +188,7 @@ func (c *Command) Run(args []string) int {
|
||||
"in a Docker container, provide the IPC_LOCK cap to the container."))
|
||||
}
|
||||
|
||||
if err := c.SetupListeners(c.UI, c.Config.SharedConfig, []string{"worker-alpn-tls"}); err != nil {
|
||||
if err := c.SetupListeners(c.UI, c.Config.SharedConfig, []string{"proxy"}); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ listener "tcp" {
|
||||
|
||||
devWorkerExtraConfig = `
|
||||
listener "tcp" {
|
||||
purpose = "worker-alpn-tls"
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
proxy_protocol_behavior = "allow_authorized"
|
||||
proxy_protocol_authorized_addrs = "127.0.0.1"
|
||||
|
||||
@@ -115,7 +115,7 @@ func TestDevWorker(t *testing.T) {
|
||||
{
|
||||
Type: "tcp",
|
||||
TLSDisable: true,
|
||||
Purpose: []string{"worker-alpn-tls"},
|
||||
Purpose: []string{"proxy"},
|
||||
ProxyProtocolBehavior: "allow_authorized",
|
||||
ProxyProtocolAuthorizedAddrs: []*sockaddr.SockAddrMarshaler{
|
||||
{SockAddr: addr},
|
||||
|
||||
@@ -5812,6 +5812,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.api.services.v1.ValidateSessionResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"title": "ID of the session job"
|
||||
},
|
||||
"scope_id": {
|
||||
"type": "string",
|
||||
"title": "The scope the job was created in"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string",
|
||||
"title": "The ID of the user that requested the session"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"title": "Type of the session (e.g. tcp, ssh, etc.)"
|
||||
},
|
||||
"endpoint": {
|
||||
"type": "string",
|
||||
"title": "The endpoint to connect to, in a manner that makes sense for the type"
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"description": "The certificate to use when connecting (or if using custom certs, to\nserve as the \"login\"). Raw DER bytes."
|
||||
},
|
||||
"private_key": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"description": "The private key to use when connecting (or if using custom certs, to pass\nas the \"password\")."
|
||||
},
|
||||
"expiration_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"title": "After this time the connection will be expired, e.g. forcefully terminated"
|
||||
},
|
||||
"worker_info": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/controller.api.services.v1.WorkerInfo"
|
||||
},
|
||||
"description": "Worker information. The first worker in the slice should be prioritized."
|
||||
}
|
||||
},
|
||||
"title": "SessionResponse contains information necessary for a client to establish a session"
|
||||
},
|
||||
"controller.api.services.v1.WorkerInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string",
|
||||
"title": "The address of the worker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller.servers.v1.Server": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -9,6 +9,7 @@ package services
|
||||
import (
|
||||
context "context"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
timestamp "github.com/golang/protobuf/ptypes/timestamp"
|
||||
servers "github.com/hashicorp/boundary/internal/servers"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
@@ -150,6 +151,225 @@ func (x *StatusResponse) GetCancelJobIds() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ValidateSessionRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The session ID from the client
|
||||
Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ValidateSessionRequest) Reset() {
|
||||
*x = ValidateSessionRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ValidateSessionRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ValidateSessionRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ValidateSessionRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ValidateSessionRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ValidateSessionRequest) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ValidateSessionRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// SessionResponse contains information necessary for a client to establish a session
|
||||
type ValidateSessionResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// ID of the session job
|
||||
Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty"`
|
||||
// The scope the job was created in
|
||||
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty"`
|
||||
// The ID of the user that requested the session
|
||||
UserId string `protobuf:"bytes,30,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
// Type of the session (e.g. tcp, ssh, etc.)
|
||||
Type string `protobuf:"bytes,40,opt,name=type,proto3" json:"type,omitempty"`
|
||||
// The endpoint to connect to, in a manner that makes sense for the type
|
||||
Endpoint string `protobuf:"bytes,50,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
|
||||
// The certificate to use when connecting (or if using custom certs, to
|
||||
// serve as the "login"). Raw DER bytes.
|
||||
Certificate []byte `protobuf:"bytes,60,opt,name=certificate,proto3" json:"certificate,omitempty"`
|
||||
// The private key to use when connecting (or if using custom certs, to pass
|
||||
// as the "password").
|
||||
PrivateKey []byte `protobuf:"bytes,70,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"`
|
||||
// After this time the connection will be expired, e.g. forcefully terminated
|
||||
ExpirationTime *timestamp.Timestamp `protobuf:"bytes,80,opt,name=expiration_time,json=expirationTime,proto3" json:"expiration_time,omitempty"`
|
||||
// Worker information. The first worker in the slice should be prioritized.
|
||||
WorkerInfo []*WorkerInfo `protobuf:"bytes,90,rep,name=worker_info,json=workerInfo,proto3" json:"worker_info,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) Reset() {
|
||||
*x = ValidateSessionResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ValidateSessionResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ValidateSessionResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ValidateSessionResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ValidateSessionResponse) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetScopeId() string {
|
||||
if x != nil {
|
||||
return x.ScopeId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetUserId() string {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetEndpoint() string {
|
||||
if x != nil {
|
||||
return x.Endpoint
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetCertificate() []byte {
|
||||
if x != nil {
|
||||
return x.Certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetPrivateKey() []byte {
|
||||
if x != nil {
|
||||
return x.PrivateKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetExpirationTime() *timestamp.Timestamp {
|
||||
if x != nil {
|
||||
return x.ExpirationTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ValidateSessionResponse) GetWorkerInfo() []*WorkerInfo {
|
||||
if x != nil {
|
||||
return x.WorkerInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WorkerInfo struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The address of the worker
|
||||
Address string `protobuf:"bytes,10,opt,name=address,proto3" json:"address,omitempty"`
|
||||
}
|
||||
|
||||
func (x *WorkerInfo) Reset() {
|
||||
*x = WorkerInfo{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *WorkerInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*WorkerInfo) ProtoMessage() {}
|
||||
|
||||
func (x *WorkerInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_api_services_v1_worker_service_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use WorkerInfo.ProtoReflect.Descriptor instead.
|
||||
func (*WorkerInfo) Descriptor() ([]byte, []int) {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *WorkerInfo) GetAddress() string {
|
||||
if x != nil {
|
||||
return x.Address
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_controller_api_services_v1_worker_service_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_controller_api_services_v1_worker_service_proto_rawDesc = []byte{
|
||||
@@ -157,37 +377,74 @@ var file_controller_api_services_v1_worker_service_proto_rawDesc = []byte{
|
||||
0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x23, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x22, 0x6c, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x52, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x63,
|
||||
0x74, 0x69, 0x76, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x14, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x49, 0x64, 0x73,
|
||||
0x22, 0x77, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x6a, 0x6f,
|
||||
0x62, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x49, 0x64, 0x73, 0x32, 0x72, 0x0a, 0x0d, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x06, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x6c, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x52, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x61,
|
||||
0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x14, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x49, 0x64,
|
||||
0x73, 0x22, 0x77, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x6a,
|
||||
0x6f, 0x62, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x49, 0x64, 0x73, 0x22, 0x28, 0x0a, 0x16, 0x56, 0x61,
|
||||
0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x02, 0x69, 0x64, 0x22, 0xde, 0x02, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
|
||||
0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
|
||||
0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75,
|
||||
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73,
|
||||
0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x28, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x69,
|
||||
0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x43, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x78,
|
||||
0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x47, 0x0a, 0x0b,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x5a, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65,
|
||||
0x72, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x26, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x32, 0xf0, 0x01,
|
||||
0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x61, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x4d, 0x5a,
|
||||
0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68,
|
||||
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x7c, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68,
|
||||
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72,
|
||||
0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -202,22 +459,30 @@ func file_controller_api_services_v1_worker_service_proto_rawDescGZIP() []byte {
|
||||
return file_controller_api_services_v1_worker_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_controller_api_services_v1_worker_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_controller_api_services_v1_worker_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_controller_api_services_v1_worker_service_proto_goTypes = []interface{}{
|
||||
(*StatusRequest)(nil), // 0: controller.api.services.v1.StatusRequest
|
||||
(*StatusResponse)(nil), // 1: controller.api.services.v1.StatusResponse
|
||||
(*servers.Server)(nil), // 2: controller.servers.v1.Server
|
||||
(*StatusRequest)(nil), // 0: controller.api.services.v1.StatusRequest
|
||||
(*StatusResponse)(nil), // 1: controller.api.services.v1.StatusResponse
|
||||
(*ValidateSessionRequest)(nil), // 2: controller.api.services.v1.ValidateSessionRequest
|
||||
(*ValidateSessionResponse)(nil), // 3: controller.api.services.v1.ValidateSessionResponse
|
||||
(*WorkerInfo)(nil), // 4: controller.api.services.v1.WorkerInfo
|
||||
(*servers.Server)(nil), // 5: controller.servers.v1.Server
|
||||
(*timestamp.Timestamp)(nil), // 6: google.protobuf.Timestamp
|
||||
}
|
||||
var file_controller_api_services_v1_worker_service_proto_depIdxs = []int32{
|
||||
2, // 0: controller.api.services.v1.StatusRequest.worker:type_name -> controller.servers.v1.Server
|
||||
2, // 1: controller.api.services.v1.StatusResponse.controllers:type_name -> controller.servers.v1.Server
|
||||
0, // 2: controller.api.services.v1.WorkerService.Status:input_type -> controller.api.services.v1.StatusRequest
|
||||
1, // 3: controller.api.services.v1.WorkerService.Status:output_type -> controller.api.services.v1.StatusResponse
|
||||
3, // [3:4] is the sub-list for method output_type
|
||||
2, // [2:3] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
5, // 0: controller.api.services.v1.StatusRequest.worker:type_name -> controller.servers.v1.Server
|
||||
5, // 1: controller.api.services.v1.StatusResponse.controllers:type_name -> controller.servers.v1.Server
|
||||
6, // 2: controller.api.services.v1.ValidateSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp
|
||||
4, // 3: controller.api.services.v1.ValidateSessionResponse.worker_info:type_name -> controller.api.services.v1.WorkerInfo
|
||||
0, // 4: controller.api.services.v1.WorkerService.Status:input_type -> controller.api.services.v1.StatusRequest
|
||||
2, // 5: controller.api.services.v1.WorkerService.ValidateSession:input_type -> controller.api.services.v1.ValidateSessionRequest
|
||||
1, // 6: controller.api.services.v1.WorkerService.Status:output_type -> controller.api.services.v1.StatusResponse
|
||||
3, // 7: controller.api.services.v1.WorkerService.ValidateSession:output_type -> controller.api.services.v1.ValidateSessionResponse
|
||||
6, // [6:8] is the sub-list for method output_type
|
||||
4, // [4:6] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_controller_api_services_v1_worker_service_proto_init() }
|
||||
@@ -250,6 +515,42 @@ func file_controller_api_services_v1_worker_service_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_api_services_v1_worker_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ValidateSessionRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_api_services_v1_worker_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ValidateSessionResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_api_services_v1_worker_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*WorkerInfo); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -257,7 +558,7 @@ func file_controller_api_services_v1_worker_service_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_controller_api_services_v1_worker_service_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
@@ -284,6 +585,7 @@ const _ = grpc.SupportPackageIsVersion6
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type WorkerServiceClient interface {
|
||||
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
|
||||
ValidateSession(ctx context.Context, in *ValidateSessionRequest, opts ...grpc.CallOption) (*ValidateSessionResponse, error)
|
||||
}
|
||||
|
||||
type workerServiceClient struct {
|
||||
@@ -303,9 +605,19 @@ func (c *workerServiceClient) Status(ctx context.Context, in *StatusRequest, opt
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *workerServiceClient) ValidateSession(ctx context.Context, in *ValidateSessionRequest, opts ...grpc.CallOption) (*ValidateSessionResponse, error) {
|
||||
out := new(ValidateSessionResponse)
|
||||
err := c.cc.Invoke(ctx, "/controller.api.services.v1.WorkerService/ValidateSession", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// WorkerServiceServer is the server API for WorkerService service.
|
||||
type WorkerServiceServer interface {
|
||||
Status(context.Context, *StatusRequest) (*StatusResponse, error)
|
||||
ValidateSession(context.Context, *ValidateSessionRequest) (*ValidateSessionResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedWorkerServiceServer can be embedded to have forward compatible implementations.
|
||||
@@ -315,6 +627,9 @@ type UnimplementedWorkerServiceServer struct {
|
||||
func (*UnimplementedWorkerServiceServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Status not implemented")
|
||||
}
|
||||
func (*UnimplementedWorkerServiceServer) ValidateSession(context.Context, *ValidateSessionRequest) (*ValidateSessionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ValidateSession not implemented")
|
||||
}
|
||||
|
||||
func RegisterWorkerServiceServer(s *grpc.Server, srv WorkerServiceServer) {
|
||||
s.RegisterService(&_WorkerService_serviceDesc, srv)
|
||||
@@ -338,6 +653,24 @@ func _WorkerService_Status_Handler(srv interface{}, ctx context.Context, dec fun
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WorkerService_ValidateSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ValidateSessionRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WorkerServiceServer).ValidateSession(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/controller.api.services.v1.WorkerService/ValidateSession",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WorkerServiceServer).ValidateSession(ctx, req.(*ValidateSessionRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _WorkerService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "controller.api.services.v1.WorkerService",
|
||||
HandlerType: (*WorkerServiceServer)(nil),
|
||||
@@ -346,6 +679,10 @@ var _WorkerService_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Status",
|
||||
Handler: _WorkerService_Status_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ValidateSession",
|
||||
Handler: _WorkerService_ValidateSession_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "controller/api/services/v1/worker_service.proto",
|
||||
|
||||
@@ -22,7 +22,7 @@ const (
|
||||
// KeyPurposeTokens is used for token encryption
|
||||
KeyPurposeTokens
|
||||
|
||||
// KeyPurposeSessions is used for session encryption
|
||||
// KeyPurposeSessions is used as a base key to derive session-specific encryption keys
|
||||
KeyPurposeSessions
|
||||
)
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ package controller.api.services.v1;
|
||||
|
||||
option go_package = "github.com/hashicorp/boundary/internal/gen/controller/api/services;services";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "controller/servers/v1/servers.proto";
|
||||
|
||||
service WorkerService {
|
||||
rpc Status(StatusRequest) returns (StatusResponse) {}
|
||||
rpc ValidateSession(ValidateSessionRequest) returns (ValidateSessionResponse) {}
|
||||
}
|
||||
|
||||
message StatusRequest {
|
||||
@@ -31,3 +33,45 @@ message StatusResponse {
|
||||
// next heartbeat, and we can move the job to canceled state.
|
||||
repeated string cancel_job_ids = 20;
|
||||
}
|
||||
|
||||
message ValidateSessionRequest {
|
||||
// The session ID from the client
|
||||
string id = 10;
|
||||
}
|
||||
|
||||
// SessionResponse contains information necessary for a client to establish a session
|
||||
message ValidateSessionResponse {
|
||||
// ID of the session job
|
||||
string id = 10;
|
||||
|
||||
// The scope the job was created in
|
||||
string scope_id = 20;
|
||||
|
||||
// The ID of the user that requested the session
|
||||
string user_id = 30;
|
||||
|
||||
// Type of the session (e.g. tcp, ssh, etc.)
|
||||
string type = 40;
|
||||
|
||||
// The endpoint to connect to, in a manner that makes sense for the type
|
||||
string endpoint = 50;
|
||||
|
||||
// The certificate to use when connecting (or if using custom certs, to
|
||||
// serve as the "login"). Raw DER bytes.
|
||||
bytes certificate = 60;
|
||||
|
||||
// The private key to use when connecting (or if using custom certs, to pass
|
||||
// as the "password").
|
||||
bytes private_key = 70;
|
||||
|
||||
// After this time the connection will be expired, e.g. forcefully terminated
|
||||
google.protobuf.Timestamp expiration_time = 80;
|
||||
|
||||
// Worker information. The first worker in the slice should be prioritized.
|
||||
repeated WorkerInfo worker_info = 90;
|
||||
}
|
||||
|
||||
message WorkerInfo {
|
||||
// The address of the worker
|
||||
string address = 10;
|
||||
}
|
||||
@@ -35,6 +35,7 @@ type Controller struct {
|
||||
|
||||
// Used for testing
|
||||
workerStatusUpdateTimes *sync.Map
|
||||
jobMap *sync.Map
|
||||
|
||||
// Repo factory methods
|
||||
AuthTokenRepoFn common.AuthTokenRepoFactory
|
||||
@@ -54,6 +55,7 @@ func New(conf *Config) (*Controller, error) {
|
||||
conf: conf,
|
||||
logger: conf.Logger.Named("controller"),
|
||||
workerStatusUpdateTimes: new(sync.Map),
|
||||
jobMap: new(sync.Map),
|
||||
}
|
||||
|
||||
c.started.Store(false)
|
||||
|
||||
@@ -2,8 +2,14 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -14,11 +20,16 @@ import (
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/accounts"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/authmethods"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/host_sets"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/sessions"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/shared-secure-libs/configutil"
|
||||
"github.com/hashicorp/vault/sdk/helper/base62"
|
||||
"github.com/hashicorp/vault/sdk/helper/strutil"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
|
||||
@@ -31,6 +42,8 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/scopes"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/handlers/users"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type HandlerProperties struct {
|
||||
@@ -49,7 +62,7 @@ func (c *Controller) handler(props HandlerProperties) (http.Handler, error) {
|
||||
return nil, err
|
||||
}
|
||||
mux.Handle("/v1/", h)
|
||||
|
||||
mux.Handle("/jobtesting", jobTestingHandler(c))
|
||||
mux.Handle("/", handleUi(c))
|
||||
|
||||
corsWrappedHandler := wrapHandlerWithCors(mux, props)
|
||||
@@ -311,6 +324,108 @@ func wrapHandlerWithCors(h http.Handler, props HandlerProperties) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func jobTestingHandler(c *Controller) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
errorResp := func(e error) {
|
||||
w.Write([]byte(e.Error()))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
endpoint := r.URL.Query().Get("endpoint")
|
||||
if endpoint == "" {
|
||||
errorResp(errors.New("missing endpoint query param"))
|
||||
return
|
||||
}
|
||||
|
||||
timeout := 15 * time.Second
|
||||
var err error
|
||||
if t := r.URL.Query().Get("timeout"); t != "" {
|
||||
if timeout, err = time.ParseDuration(t); err != nil {
|
||||
errorResp(fmt.Errorf("error parsing timeout: %w", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var workers []*services.WorkerInfo
|
||||
repo, err := c.ServersRepoFn()
|
||||
if err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
servers, err := repo.ListServers(r.Context(), servers.ServerTypeWorker)
|
||||
if err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
for _, v := range servers {
|
||||
workers = append(workers, &services.WorkerInfo{Address: v.Address})
|
||||
}
|
||||
|
||||
wrapper, err := c.kms.GetWrapper(r.Context(), scope.Global.String(), kms.KeyPurposeSessions)
|
||||
if err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
jobId, err := base62.Random(10)
|
||||
if err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
jobId = "s_" + jobId
|
||||
pubKey, privKey, err := sessions.DeriveED25519Key(wrapper, "u_1234567890", jobId)
|
||||
|
||||
template := &x509.Certificate{
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
},
|
||||
DNSNames: []string{jobId},
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign,
|
||||
SerialNumber: big.NewInt(mathrand.Int63()),
|
||||
NotBefore: time.Now().Add(-1 * time.Minute),
|
||||
NotAfter: time.Now().Add(5 * time.Minute),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
certBytes, err := x509.CreateCertificate(rand.Reader, template, template, pubKey, privKey)
|
||||
if err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
|
||||
ret := &services.ValidateSessionResponse{
|
||||
Id: jobId,
|
||||
ScopeId: scope.Global.String(),
|
||||
UserId: "u_1234567890",
|
||||
Type: "tcp",
|
||||
Endpoint: endpoint,
|
||||
Certificate: certBytes,
|
||||
PrivateKey: privKey,
|
||||
WorkerInfo: workers,
|
||||
ExpirationTime: ×tamppb.Timestamp{Seconds: time.Now().Add(timeout).Unix()},
|
||||
}
|
||||
|
||||
marshaled, err := proto.Marshal(ret)
|
||||
if err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := w.Write([]byte(base64.RawStdEncoding.EncodeToString(marshaled))); err != nil {
|
||||
errorResp(err)
|
||||
return
|
||||
}
|
||||
|
||||
ret.PrivateKey = nil
|
||||
c.jobMap.Store(jobId, ret)
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAddrMarshaler, rejectNotPresent, rejectNonAuthz bool, hopSkips int) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"time"
|
||||
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/sessions"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -14,21 +16,27 @@ import (
|
||||
)
|
||||
|
||||
type workerServiceServer struct {
|
||||
logger hclog.Logger
|
||||
repoFn common.ServersRepoFactory
|
||||
updateTimes *sync.Map
|
||||
logger hclog.Logger
|
||||
repoFn common.ServersRepoFactory
|
||||
updateTimes *sync.Map
|
||||
kms *kms.Kms
|
||||
jobMap *sync.Map
|
||||
jobCancelMap *sync.Map
|
||||
}
|
||||
|
||||
func NewWorkerServiceServer(logger hclog.Logger, repoFn common.ServersRepoFactory, updateTimes *sync.Map) *workerServiceServer {
|
||||
func NewWorkerServiceServer(logger hclog.Logger, repoFn common.ServersRepoFactory, updateTimes *sync.Map, kms *kms.Kms, jobMap *sync.Map) *workerServiceServer {
|
||||
return &workerServiceServer{
|
||||
logger: logger,
|
||||
repoFn: repoFn,
|
||||
updateTimes: updateTimes,
|
||||
logger: logger,
|
||||
repoFn: repoFn,
|
||||
updateTimes: updateTimes,
|
||||
kms: kms,
|
||||
jobMap: jobMap,
|
||||
jobCancelMap: new(sync.Map),
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) {
|
||||
ws.logger.Trace("got status request from worker", "name", req.Worker.Name, "address", req.Worker.Address)
|
||||
ws.logger.Trace("got status request from worker", "name", req.Worker.Name, "address", req.Worker.Address, "active_jobs", req.ActiveJobIds)
|
||||
ws.updateTimes.Store(req.Worker.Name, time.Now())
|
||||
repo, err := ws.repoFn()
|
||||
if err != nil {
|
||||
@@ -41,7 +49,53 @@ func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusReques
|
||||
ws.logger.Error("error storing worker status", "error", err)
|
||||
return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error storing worker status: %v", err)
|
||||
}
|
||||
return &pbs.StatusResponse{
|
||||
ret := &pbs.StatusResponse{
|
||||
Controllers: controllers,
|
||||
}, nil
|
||||
}
|
||||
ws.jobCancelMap.Range(func(key, value interface{}) bool {
|
||||
ret.CancelJobIds = append(ret.CancelJobIds, key.(string))
|
||||
return true
|
||||
})
|
||||
for _, id := range ret.CancelJobIds {
|
||||
ws.jobCancelMap.Delete(id)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ws *workerServiceServer) ValidateSession(ctx context.Context, req *pbs.ValidateSessionRequest) (*pbs.ValidateSessionResponse, error) {
|
||||
ws.logger.Trace("got validate session request from worker", "job_id", req.GetId())
|
||||
|
||||
// Look up the job info
|
||||
storedSessionInfo, loaded := ws.jobMap.LoadAndDelete(req.GetId())
|
||||
if !loaded {
|
||||
return &pbs.ValidateSessionResponse{}, status.Errorf(codes.PermissionDenied, "Unknown job ID: %v", req.GetId())
|
||||
}
|
||||
sessionInfo := storedSessionInfo.(*pbs.ValidateSessionResponse)
|
||||
|
||||
wrapper, err := ws.kms.GetWrapper(ctx, sessionInfo.ScopeId, kms.KeyPurposeSessions)
|
||||
if err != nil {
|
||||
return &pbs.ValidateSessionResponse{}, status.Errorf(codes.Internal, "Error getting sessions wrapper: %v", err)
|
||||
}
|
||||
|
||||
// Derive the private key, which should match. Deriving on both ends allows
|
||||
// us to not store it in the DB.
|
||||
_, privKey, err := sessions.DeriveED25519Key(wrapper, sessionInfo.GetUserId(), req.GetId())
|
||||
if err != nil {
|
||||
return &pbs.ValidateSessionResponse{}, status.Errorf(codes.Internal, "Error deriving session key: %v", err)
|
||||
}
|
||||
|
||||
if sessionInfo.ExpirationTime.GetSeconds() > 0 {
|
||||
timeDiff := time.Until(sessionInfo.GetExpirationTime().AsTime())
|
||||
if timeDiff < 0 {
|
||||
return &pbs.ValidateSessionResponse{}, status.Errorf(codes.OutOfRange, "Session has already expired")
|
||||
}
|
||||
defer func() {
|
||||
time.AfterFunc(timeDiff, func() {
|
||||
ws.jobCancelMap.Store(req.GetId(), true)
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
sessionInfo.PrivateKey = privKey
|
||||
return sessionInfo, nil
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (c *Controller) startListeners() error {
|
||||
// Clear out in case this is a second start of the controller
|
||||
ln.Mux.UnregisterProto(alpnmux.DefaultProto)
|
||||
l, err := ln.Mux.RegisterProto(alpnmux.DefaultProto, &tls.Config{
|
||||
GetConfigForClient: c.validateWorkerTLS,
|
||||
GetConfigForClient: c.validateWorkerTls,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting sub-listener for worker proto: %w", err)
|
||||
@@ -120,7 +120,7 @@ func (c *Controller) startListeners() error {
|
||||
grpc.MaxRecvMsgSize(math.MaxInt32),
|
||||
grpc.MaxSendMsgSize(math.MaxInt32),
|
||||
)
|
||||
services.RegisterWorkerServiceServer(workerServer, workers.NewWorkerServiceServer(c.logger.Named("worker-handler"), c.ServersRepoFn, c.workerStatusUpdateTimes))
|
||||
services.RegisterWorkerServiceServer(workerServer, workers.NewWorkerServiceServer(c.logger.Named("worker-handler"), c.ServersRepoFn, c.workerStatusUpdateTimes, c.kms, c.jobMap))
|
||||
|
||||
interceptor := newInterceptingListener(c, l)
|
||||
ln.ALPNListener = interceptor
|
||||
@@ -144,7 +144,7 @@ func (c *Controller) startListeners() error {
|
||||
} else {
|
||||
err = configureForCluster(ln)
|
||||
}
|
||||
case "worker-alpn-tls":
|
||||
case "proxy":
|
||||
// Do nothing, in a dev mode we might see it here
|
||||
default:
|
||||
err = fmt.Errorf("unknown listener purpose %q", purpose)
|
||||
|
||||
@@ -20,7 +20,7 @@ type workerAuthEntry struct {
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func (c Controller) validateWorkerTLS(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
func (c Controller) validateWorkerTls(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
for _, p := range hello.SupportedProtos {
|
||||
switch {
|
||||
case strings.HasPrefix(p, "v1workerauth-"):
|
||||
@@ -84,7 +84,6 @@ func (c Controller) v1WorkerAuthConfig(protos []string) (*tls.Config, *base.Work
|
||||
NextProtos: []string{firstMatchProto},
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
|
||||
return tlsConfig, info, nil
|
||||
}
|
||||
@@ -16,6 +16,17 @@ const (
|
||||
defaultLiveness = 15 * time.Second
|
||||
)
|
||||
|
||||
type ServerType string
|
||||
|
||||
const (
|
||||
ServerTypeController ServerType = "controller"
|
||||
ServerTypeWorker ServerType = "worker"
|
||||
)
|
||||
|
||||
func (s ServerType) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// Repository is the servers database repository
|
||||
type Repository struct {
|
||||
reader db.Reader
|
||||
@@ -44,7 +55,7 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms) (*Repository, error)
|
||||
|
||||
// list will return a listing of resources and honor the WithLimit option or the
|
||||
// repo defaultLimit
|
||||
func (r *Repository) ListServers(ctx context.Context, serverType string, opt ...Option) ([]*Server, error) {
|
||||
func (r *Repository) ListServers(ctx context.Context, serverType ServerType, opt ...Option) ([]*Server, error) {
|
||||
opts := getOpts(opt...)
|
||||
liveness := opts.withLiveness
|
||||
if liveness == 0 {
|
||||
@@ -107,7 +118,7 @@ func (r *Repository) UpsertServer(ctx context.Context, server *Server, opt ...Op
|
||||
return nil, int(rowsAffected), nil
|
||||
}
|
||||
// Fetch current controllers to feed to the workers
|
||||
controllers, err := r.ListServers(ctx, resource.Controller.String())
|
||||
controllers, err := r.ListServers(ctx, ServerTypeController)
|
||||
return controllers, len(controllers), err
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
@@ -25,20 +26,6 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type controllerConnection struct {
|
||||
controllerAddr string
|
||||
client services.WorkerServiceClient
|
||||
}
|
||||
|
||||
func newControllerConnection(controllerAddr string, client services.WorkerServiceClient) *controllerConnection {
|
||||
ret := &controllerConnection{
|
||||
controllerAddr: controllerAddr,
|
||||
client: client,
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (w *Worker) startControllerConnections() error {
|
||||
initialAddrs := make([]resolver.Address, 0, len(w.conf.RawConfig.Worker.Controllers))
|
||||
for _, addr := range w.conf.RawConfig.Worker.Controllers {
|
||||
@@ -52,13 +39,15 @@ func (w *Worker) startControllerConnections() error {
|
||||
initialAddrs = append(initialAddrs, resolver.Address{Addr: fmt.Sprintf("%s:%s", host, port)})
|
||||
}
|
||||
|
||||
if len(initialAddrs) == 0 {
|
||||
return errors.New("no initial controller addresses found")
|
||||
}
|
||||
|
||||
w.Resolver().InitialState(resolver.State{
|
||||
Addresses: initialAddrs,
|
||||
})
|
||||
for _, addr := range initialAddrs {
|
||||
if err := w.createClientConn(addr.Addr); err != nil {
|
||||
return fmt.Errorf("error making client connection to controller: %w", err)
|
||||
}
|
||||
if err := w.createClientConn(initialAddrs[0].Addr); err != nil {
|
||||
return fmt.Errorf("error making client connection to controller: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -123,7 +112,7 @@ func (w *Worker) createClientConn(addr string) error {
|
||||
}
|
||||
|
||||
client := services.NewWorkerServiceClient(cc)
|
||||
w.controllerConns.Store(addr, newControllerConnection(addr, client))
|
||||
w.controllerConn.Store(client)
|
||||
|
||||
w.logger.Info("connected to controller", "address", addr)
|
||||
return nil
|
||||
@@ -257,7 +246,6 @@ func (w Worker) workerAuthTLSConfig() (*tls.Config, *base.WorkerAuthInfo, error)
|
||||
NextProtos: nextProtos,
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
|
||||
return tlsConfig, info, nil
|
||||
}
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/shared-secure-libs/configutil"
|
||||
"nhooyr.io/websocket"
|
||||
)
|
||||
|
||||
type HandlerProperties struct {
|
||||
@@ -15,25 +17,67 @@ type HandlerProperties struct {
|
||||
|
||||
// Handler returns an http.Handler for the API. This can be used on
|
||||
// its own to mount the Vault API within another web server.
|
||||
func (c *Worker) Handler(props HandlerProperties) http.Handler {
|
||||
func (w *Worker) handler(props HandlerProperties) http.Handler {
|
||||
// Create the muxer to handle the actual endpoints
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/v1/", handleDummy())
|
||||
mux.Handle("/v1/proxy", w.handleProxy())
|
||||
|
||||
genericWrappedHandler := c.wrapGenericHandler(mux, props)
|
||||
genericWrappedHandler := w.wrapGenericHandler(mux, props)
|
||||
|
||||
return genericWrappedHandler
|
||||
}
|
||||
|
||||
func handleDummy() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"foo": "bar"}`))
|
||||
func (w *Worker) handleProxy() http.HandlerFunc {
|
||||
return http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) {
|
||||
if r.TLS == nil {
|
||||
w.logger.Error("no request TLS information found")
|
||||
wr.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
jobId := r.TLS.ServerName
|
||||
|
||||
jobInfoRaw, valid := w.jobInfoMap.LoadAndDelete(jobId)
|
||||
if !valid {
|
||||
w.logger.Error("job not found in info map", "job_id", jobId)
|
||||
wr.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
jobInfo := jobInfoRaw.(*services.ValidateSessionResponse)
|
||||
|
||||
opts := &websocket.AcceptOptions{
|
||||
Subprotocols: []string{globals.TcpProxyV1},
|
||||
}
|
||||
conn, err := websocket.Accept(wr, r, opts)
|
||||
if err != nil {
|
||||
w.logger.Error("error during websocket upgrade", "error", err)
|
||||
wr.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Later calls will cause this to noop if they return a different status
|
||||
defer conn.Close(websocket.StatusNormalClosure, "done")
|
||||
|
||||
connCtx, connCancel := context.WithCancel(r.Context())
|
||||
w.cancellationMap.Store(jobId, connCancel)
|
||||
defer func() {
|
||||
cancel, loaded := w.cancellationMap.LoadAndDelete(jobId)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
cancel.(context.CancelFunc)()
|
||||
}()
|
||||
|
||||
switch conn.Subprotocol() {
|
||||
case globals.TcpProxyV1:
|
||||
w.handleTcpProxyV1(connCtx, conn, jobInfo)
|
||||
default:
|
||||
conn.Close(websocket.StatusProtocolError, "unsupported-protocol")
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Worker) wrapGenericHandler(h http.Handler, props HandlerProperties) http.Handler {
|
||||
func (w *Worker) wrapGenericHandler(h http.Handler, props HandlerProperties) http.Handler {
|
||||
var maxRequestDuration time.Duration
|
||||
var maxRequestSize int64
|
||||
if props.ListenerConfig != nil {
|
||||
@@ -46,9 +90,9 @@ func (c *Worker) wrapGenericHandler(h http.Handler, props HandlerProperties) htt
|
||||
if maxRequestSize == 0 {
|
||||
maxRequestSize = globals.DefaultMaxRequestSize
|
||||
}
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
return http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) {
|
||||
// Set the Cache-Control header for all responses returned
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
wr.Header().Set("Cache-Control", "no-store")
|
||||
|
||||
// Start with the request context
|
||||
ctx := r.Context()
|
||||
@@ -62,9 +106,8 @@ func (c *Worker) wrapGenericHandler(h http.Handler, props HandlerProperties) htt
|
||||
ctx = context.WithValue(ctx, globals.ContextOriginalRequestPathTypeKey, r.URL.Path)
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
h.ServeHTTP(wr, r)
|
||||
cancelFunc()
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
)
|
||||
|
||||
const (
|
||||
validateSessionTimeout = 90 * time.Second
|
||||
)
|
||||
|
||||
func (w *Worker) getJobTls(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
var jobId string
|
||||
switch {
|
||||
case strings.HasPrefix(hello.ServerName, "s_"):
|
||||
jobId = hello.ServerName
|
||||
default:
|
||||
return nil, fmt.Errorf("could not find job ID in SNI")
|
||||
}
|
||||
|
||||
rawConn := w.controllerConn.Load()
|
||||
if rawConn == nil {
|
||||
return nil, errors.New("could not get a controller client")
|
||||
}
|
||||
conn, ok := rawConn.(services.WorkerServiceClient)
|
||||
if !ok {
|
||||
return nil, errors.New("could not cast atomic controller client to the real thing")
|
||||
}
|
||||
if conn == nil {
|
||||
return nil, errors.New("controller client is nil")
|
||||
}
|
||||
|
||||
timeoutContext, cancel := context.WithTimeout(w.baseContext, validateSessionTimeout)
|
||||
defer cancel()
|
||||
|
||||
resp, err := conn.ValidateSession(timeoutContext, &services.ValidateSessionRequest{
|
||||
Id: jobId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error validating session: %w", err)
|
||||
}
|
||||
|
||||
parsedCert, err := x509.ParseCertificate(resp.GetCertificate())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing session certificate: %w", err)
|
||||
}
|
||||
|
||||
if len(parsedCert.DNSNames) != 1 {
|
||||
return nil, fmt.Errorf("invalid length of DNS names (%d) in parsed certificate", len(parsedCert.DNSNames))
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AddCert(parsedCert)
|
||||
|
||||
tlsConf := &tls.Config{
|
||||
Certificates: []tls.Certificate{
|
||||
{
|
||||
Certificate: [][]byte{resp.GetCertificate()},
|
||||
PrivateKey: ed25519.PrivateKey(resp.GetPrivateKey()),
|
||||
Leaf: parsedCert,
|
||||
},
|
||||
},
|
||||
ServerName: parsedCert.DNSNames[0],
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: certPool,
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
|
||||
// TODO: Periodicially clean this up. We can't rely on things in here but
|
||||
// not in cancellation because they could be on the way to being
|
||||
// established. However, since cert lifetimes are short, we can simply range
|
||||
// through and remove values that are expired.
|
||||
w.jobInfoMap.Store(jobId, resp)
|
||||
|
||||
return tlsConf, nil
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-alpnmux"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
@@ -11,24 +18,74 @@ func (w *Worker) startListeners() error {
|
||||
servers := make([]func(), 0, len(w.conf.Listeners))
|
||||
|
||||
for _, ln := range w.conf.Listeners {
|
||||
var err error
|
||||
for _, purpose := range ln.Config.Purpose {
|
||||
switch purpose {
|
||||
case "api", "cluster":
|
||||
// Do nothing, in dev mode we might see it here
|
||||
case "worker-alpn-tls":
|
||||
if w.listeningAddress != "" {
|
||||
return errors.New("more than one listening address found")
|
||||
}
|
||||
w.listeningAddress = ln.Config.Address
|
||||
w.logger.Info("reporting listening address to controllers", "address", w.listeningAddress)
|
||||
// TODO: other stuff
|
||||
// TODO: once we have an actual listener, record in w.listeningAddress the actual address with port
|
||||
// We may have this in dev mode; ignore
|
||||
continue
|
||||
|
||||
case "proxy":
|
||||
// Do nothing; handle below
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unknown listener purpose %q", purpose)
|
||||
return fmt.Errorf("unknown listener purpose %q", purpose)
|
||||
}
|
||||
|
||||
if w.listeningAddress != "" {
|
||||
return errors.New("more than one listening address found")
|
||||
}
|
||||
|
||||
handler := w.handler(HandlerProperties{
|
||||
ListenerConfig: ln.Config,
|
||||
})
|
||||
|
||||
cancelCtx := w.baseContext
|
||||
|
||||
server := &http.Server{
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
IdleTimeout: 5 * time.Minute,
|
||||
ErrorLog: w.logger.StandardLogger(nil),
|
||||
BaseContext: func(net.Listener) context.Context {
|
||||
return cancelCtx
|
||||
},
|
||||
}
|
||||
ln.HTTPServer = server
|
||||
|
||||
if ln.Config.HTTPReadHeaderTimeout > 0 {
|
||||
server.ReadHeaderTimeout = ln.Config.HTTPReadHeaderTimeout
|
||||
}
|
||||
if ln.Config.HTTPReadTimeout > 0 {
|
||||
server.ReadTimeout = ln.Config.HTTPReadTimeout
|
||||
}
|
||||
if ln.Config.HTTPWriteTimeout > 0 {
|
||||
server.WriteTimeout = ln.Config.HTTPWriteTimeout
|
||||
}
|
||||
if ln.Config.HTTPIdleTimeout > 0 {
|
||||
server.IdleTimeout = ln.Config.HTTPIdleTimeout
|
||||
}
|
||||
|
||||
// Clear out in case this is a second start of the controller
|
||||
ln.Mux.UnregisterProto(alpnmux.DefaultProto)
|
||||
ln.Mux.UnregisterProto(alpnmux.NoProto)
|
||||
l, err := ln.Mux.RegisterProto(alpnmux.DefaultProto, &tls.Config{
|
||||
GetConfigForClient: w.getJobTls,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error getting tls listener: %w", err)
|
||||
}
|
||||
if l == nil {
|
||||
return errors.New("could not get tls listener")
|
||||
}
|
||||
|
||||
servers = append(servers, func() {
|
||||
go server.Serve(l)
|
||||
})
|
||||
|
||||
if w.listeningAddress == "" {
|
||||
w.listeningAddress = l.Addr().String()
|
||||
w.logger.Info("reporting listening address to controllers", "address", w.listeningAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,15 +98,26 @@ func (w *Worker) startListeners() error {
|
||||
}
|
||||
|
||||
func (w *Worker) stopListeners() error {
|
||||
var retErr *multierror.Error
|
||||
serverWg := new(sync.WaitGroup)
|
||||
for _, ln := range w.conf.Listeners {
|
||||
if ln.ALPNListener != nil {
|
||||
if err := ln.ALPNListener.Close(); err != nil {
|
||||
retErr = multierror.Append(retErr, err)
|
||||
}
|
||||
}
|
||||
localLn := ln
|
||||
serverWg.Add(1)
|
||||
go func() {
|
||||
defer serverWg.Done()
|
||||
|
||||
if !w.conf.RawConfig.DevController {
|
||||
shutdownKill, shutdownKillCancel := context.WithTimeout(w.baseContext, localLn.Config.MaxRequestDuration)
|
||||
defer shutdownKillCancel()
|
||||
|
||||
if localLn.HTTPServer != nil {
|
||||
localLn.HTTPServer.Shutdown(shutdownKill)
|
||||
}
|
||||
}()
|
||||
}
|
||||
serverWg.Wait()
|
||||
|
||||
var retErr *multierror.Error
|
||||
if !w.conf.RawConfig.DevController {
|
||||
for _, ln := range w.conf.Listeners {
|
||||
if err := ln.Mux.Close(); err != nil {
|
||||
retErr = multierror.Append(retErr, err)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
@@ -16,6 +17,11 @@ const (
|
||||
statusInterval = 2 * time.Second
|
||||
)
|
||||
|
||||
type LastStatusInformation struct {
|
||||
*pbs.StatusResponse
|
||||
StatusTime time.Time
|
||||
}
|
||||
|
||||
func (w *Worker) startStatusTicking(cancelCtx context.Context) {
|
||||
go func() {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
@@ -40,43 +46,51 @@ func (w *Worker) startStatusTicking(cancelCtx context.Context) {
|
||||
return
|
||||
|
||||
case <-timer.C:
|
||||
w.controllerConns.Range(func(_, v interface{}) bool {
|
||||
// If something is removed from the map while ranging, ignore it
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
c := v.(*controllerConnection)
|
||||
result, err := c.client.Status(cancelCtx, &pbs.StatusRequest{
|
||||
Worker: &servers.Server{
|
||||
PrivateId: w.conf.RawConfig.Worker.Name,
|
||||
Name: w.conf.RawConfig.Worker.Name,
|
||||
Type: resource.Worker.String(),
|
||||
Description: w.conf.RawConfig.Worker.Description,
|
||||
Address: w.listeningAddress,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
w.logger.Error("error making status request to controller", "error", err)
|
||||
} else {
|
||||
w.logger.Trace("successfully sent status to controller")
|
||||
addrs := make([]resolver.Address, 0, len(result.Controllers))
|
||||
strAddrs := make([]string, 0, len(result.Controllers))
|
||||
for _, v := range result.Controllers {
|
||||
addrs = append(addrs, resolver.Address{Addr: v.Address})
|
||||
strAddrs = append(strAddrs, v.Address)
|
||||
}
|
||||
w.Resolver().UpdateState(resolver.State{Addresses: addrs})
|
||||
w.logger.Trace("found controllers", "addresses", strAddrs)
|
||||
w.lastStatusSuccess.Store(time.Now())
|
||||
}
|
||||
var activeJobs []string
|
||||
w.cancellationMap.Range(func(key, value interface{}) bool {
|
||||
activeJobs = append(activeJobs, key.(string))
|
||||
return true
|
||||
})
|
||||
client := w.controllerConn.Load().(services.WorkerServiceClient)
|
||||
result, err := client.Status(cancelCtx, &pbs.StatusRequest{
|
||||
ActiveJobIds: activeJobs,
|
||||
Worker: &servers.Server{
|
||||
PrivateId: w.conf.RawConfig.Worker.Name,
|
||||
Name: w.conf.RawConfig.Worker.Name,
|
||||
Type: resource.Worker.String(),
|
||||
Description: w.conf.RawConfig.Worker.Description,
|
||||
Address: w.listeningAddress,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
w.logger.Error("error making status request to controller", "error", err)
|
||||
} else {
|
||||
w.logger.Trace("successfully sent status to controller")
|
||||
addrs := make([]resolver.Address, 0, len(result.Controllers))
|
||||
strAddrs := make([]string, 0, len(result.Controllers))
|
||||
for _, v := range result.Controllers {
|
||||
addrs = append(addrs, resolver.Address{Addr: v.Address})
|
||||
strAddrs = append(strAddrs, v.Address)
|
||||
}
|
||||
w.Resolver().UpdateState(resolver.State{Addresses: addrs})
|
||||
w.logger.Trace("found controllers", "addresses", strAddrs)
|
||||
w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now()})
|
||||
|
||||
for _, id := range result.GetCancelJobIds() {
|
||||
if cancel, ok := w.cancellationMap.LoadAndDelete(id); ok {
|
||||
cancel.(context.CancelFunc)()
|
||||
w.logger.Info("canceled job", "job_id", id)
|
||||
} else {
|
||||
w.logger.Warn("asked to cancel job but could not find a cancellation function for it", "job_id", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
timer.Reset(getRandomInterval())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (w *Worker) LastStatusSuccess() time.Time {
|
||||
return w.lastStatusSuccess.Load().(time.Time)
|
||||
func (w *Worker) LastStatusSuccess() *LastStatusInformation {
|
||||
return w.lastStatusSuccess.Load().(*LastStatusInformation)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"nhooyr.io/websocket"
|
||||
)
|
||||
|
||||
func (w *Worker) handleTcpProxyV1(jobCtx context.Context, conn *websocket.Conn, jobInfo *services.ValidateSessionResponse) {
|
||||
remoteConn, err := net.Dial("tcp", jobInfo.Endpoint)
|
||||
if err != nil {
|
||||
w.logger.Error("error dialing endpoint", "error", err, "endpoint", jobInfo.Endpoint)
|
||||
conn.Close(websocket.StatusInternalError, "endpoint-dialing")
|
||||
return
|
||||
}
|
||||
// Assert this for better Go 1.11 splice support
|
||||
tcpRemoteConn := remoteConn.(*net.TCPConn)
|
||||
|
||||
// Get a wrapped net.Conn so we can use io.Copy
|
||||
netConn := websocket.NetConn(jobCtx, conn, websocket.MessageBinary)
|
||||
|
||||
connWg := new(sync.WaitGroup)
|
||||
connWg.Add(2)
|
||||
go func() {
|
||||
defer connWg.Done()
|
||||
_, err := io.Copy(netConn, tcpRemoteConn)
|
||||
w.logger.Debug("copy from client to endpoint done", "error", err)
|
||||
}()
|
||||
go func() {
|
||||
defer connWg.Done()
|
||||
_, err := io.Copy(tcpRemoteConn, netConn)
|
||||
w.logger.Debug("copy from endpoint to client done", "error", err)
|
||||
}()
|
||||
connWg.Wait()
|
||||
}
|
||||
@@ -49,15 +49,10 @@ func (tw *TestWorker) Name() string {
|
||||
|
||||
func (tw *TestWorker) ControllerAddrs() []string {
|
||||
var addrs []string
|
||||
tw.w.controllerConns.Range(func(_, v interface{}) bool {
|
||||
// If something is removed from the map while ranging, ignore it
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
c := v.(*controllerConnection)
|
||||
addrs = append(addrs, c.controllerAddr)
|
||||
return true
|
||||
})
|
||||
lastStatus := tw.w.LastStatusSuccess()
|
||||
for _, v := range lastStatus.GetControllers() {
|
||||
addrs = append(addrs, v.Address)
|
||||
}
|
||||
|
||||
return addrs
|
||||
}
|
||||
@@ -68,7 +63,7 @@ func (tw *TestWorker) ProxyAddrs() []string {
|
||||
}
|
||||
|
||||
for _, listener := range tw.b.Listeners {
|
||||
if listener.Config.Purpose[0] == "worker-alpn-tls" {
|
||||
if listener.Config.Purpose[0] == "proxy" {
|
||||
tcpAddr, ok := listener.Mux.Addr().(*net.TCPAddr)
|
||||
if !ok {
|
||||
tw.t.Fatal("could not parse address as a TCP addr")
|
||||
@@ -190,7 +185,7 @@ func NewTestWorker(t *testing.T, opts *TestWorkerOpts) *TestWorker {
|
||||
for _, listener := range opts.Config.Listeners {
|
||||
listener.RandomPort = true
|
||||
}
|
||||
if err := tw.b.SetupListeners(nil, opts.Config.SharedConfig, []string{"worker-alpn-tls"}); err != nil {
|
||||
if err := tw.b.SetupListeners(nil, opts.Config.SharedConfig, []string{"proxy"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
@@ -25,26 +24,31 @@ type Worker struct {
|
||||
baseCancel context.CancelFunc
|
||||
started ua.Bool
|
||||
|
||||
controllerConns *sync.Map
|
||||
controllerConn *atomic.Value
|
||||
lastStatusSuccess *atomic.Value
|
||||
|
||||
listeningAddress string
|
||||
|
||||
controllerResolver *atomic.Value
|
||||
controllerResolverCleanup *atomic.Value
|
||||
|
||||
jobInfoMap *sync.Map
|
||||
cancellationMap *sync.Map
|
||||
}
|
||||
|
||||
func New(conf *Config) (*Worker, error) {
|
||||
w := &Worker{
|
||||
conf: conf,
|
||||
logger: conf.Logger.Named("worker"),
|
||||
controllerConns: new(sync.Map),
|
||||
controllerConn: new(atomic.Value),
|
||||
lastStatusSuccess: new(atomic.Value),
|
||||
controllerResolver: new(atomic.Value),
|
||||
controllerResolverCleanup: new(atomic.Value),
|
||||
jobInfoMap: new(sync.Map),
|
||||
cancellationMap: new(sync.Map),
|
||||
}
|
||||
|
||||
w.lastStatusSuccess.Store(time.Time{})
|
||||
w.lastStatusSuccess.Store((*LastStatusInformation)(nil))
|
||||
w.started.Store(false)
|
||||
w.controllerResolver.Store((*manual.Resolver)(nil))
|
||||
w.controllerResolverCleanup.Store(func() {})
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package sessions
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping"
|
||||
"github.com/hashicorp/go-kms-wrapping/wrappers/aead"
|
||||
"github.com/hashicorp/go-kms-wrapping/wrappers/multiwrapper"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// DeriveED25519Key generates a key based on the scope's sessions DEK, the
|
||||
// requesting user, and the generated job ID.
|
||||
func DeriveED25519Key(wrapper wrapping.Wrapper, userId, jobId string) (ed25519.PublicKey, ed25519.PrivateKey, error) {
|
||||
var aeadWrapper *aead.Wrapper
|
||||
switch w := wrapper.(type) {
|
||||
case *multiwrapper.MultiWrapper:
|
||||
raw := w.WrapperForKeyID("__base__")
|
||||
var ok bool
|
||||
if aeadWrapper, ok = raw.(*aead.Wrapper); !ok {
|
||||
return nil, nil, errors.New("unexpected wrapper type from multiwrapper base")
|
||||
}
|
||||
case *aead.Wrapper:
|
||||
aeadWrapper = w
|
||||
default:
|
||||
return nil, nil, errors.New("unknown wrapper type")
|
||||
}
|
||||
reader := hkdf.New(sha256.New, aeadWrapper.GetKeyBytes(), []byte(jobId), []byte(userId))
|
||||
limitedReader := &io.LimitedReader{
|
||||
R: reader,
|
||||
N: 32,
|
||||
}
|
||||
return ed25519.GenerateKey(limitedReader)
|
||||
}
|
||||
Reference in new issue
Block a user