diff --git a/config/.env b/config/.env index ee0d851..b472f9c 100644 --- a/config/.env +++ b/config/.env @@ -26,6 +26,7 @@ MODEL_BACKEND_PUBLICPORT=8083 # mgmt-backend MGMT_BACKEND_HOST=mgmt-backend MGMT_BACKEND_PUBLICPORT=8084 +MGMT_BACKEND_PRIVATEPORT=3084 # influxdb INFLUXDB_HOST=influxdb @@ -39,4 +40,3 @@ JAEGER_PORT=14268 # accept jaeger.thrift directly from clients # registry REGISTRY_HOST=registry REGISTRY_PORT=5000 -REGISTRY_PREFIX=/artifact/ diff --git a/config/.env.envsubst b/config/.env.envsubst index dc7f14d..931d577 100644 --- a/config/.env.envsubst +++ b/config/.env.envsubst @@ -22,6 +22,7 @@ MODEL_BACKEND_PUBLICPORT=${MODEL_BACKEND_PUBLICPORT} # mgmt-backend MGMT_BACKEND_HOST=${MGMT_BACKEND_HOST} MGMT_BACKEND_PUBLICPORT=${MGMT_BACKEND_PUBLICPORT} +MGMT_BACKEND_PRIVATEPORT=${MGMT_BACKEND_PRIVATEPORT} # influxdb INFLUXDB_HOST=${INFLUXDB_HOST} @@ -35,4 +36,3 @@ JAEGER_PORT=${JAEGER_PORT} # registry REGISTRY_HOST=${REGISTRY_HOST} REGISTRY_PORT=${REGISTRY_PORT} -REGISTRY_PREFIX=${REGISTRY_PREFIX} diff --git a/config/base.json b/config/base.json index 628dba0..ca21205 100644 --- a/config/base.json +++ b/config/base.json @@ -34,12 +34,13 @@ "plugin/http-server": { "name": ["multi-auth", "grpc-proxy-server", "registry"], "multi-auth":{ - "grpc_server": "{{ .plugins.mgmt_grpc }}" + "grpc_server": "{{ .plugins.mgmt_public_hostport }}" }, "grpc-proxy-server": {}, "registry": { "hostport": "{{ .plugins.registry_hostport }}", - "prefix": "{{ .plugins.registry_prefix }}" + "mgmt_public_hostport": "{{ .plugins.mgmt_public_hostport }}", + "mgmt_private_hostport": "{{ .plugins.mgmt_private_hostport }}" } } }, diff --git a/config/settings-env/plugins.json b/config/settings-env/plugins.json index 6442028..4a7e1c0 100644 --- a/config/settings-env/plugins.json +++ b/config/settings-env/plugins.json @@ -1,5 +1,5 @@ { - "mgmt_grpc": "${MGMT_BACKEND_HOST}:${MGMT_BACKEND_PUBLICPORT}", - "registry_hostport": "${REGISTRY_HOST}:${REGISTRY_PORT}", - "registry_prefix": "${REGISTRY_PREFIX}" + "mgmt_public_hostport": "${MGMT_BACKEND_HOST}:${MGMT_BACKEND_PUBLICPORT}", + "mgmt_private_hostport": "${MGMT_BACKEND_HOST}:${MGMT_BACKEND_PRIVATEPORT}", + "registry_hostport": "${REGISTRY_HOST}:${REGISTRY_PORT}" } \ No newline at end of file diff --git a/registry-plugin/external.go b/registry-plugin/external.go new file mode 100644 index 0000000..a12a306 --- /dev/null +++ b/registry-plugin/external.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + + mgmtPB "github.com/instill-ai/protogen-go/core/mgmt/v1beta" +) + +const MaxPayloadSize = 1024 * 1024 * 32 + +func InitMgmtPublicServiceClient(ctx context.Context, server string, cert string, key string) (mgmtPB.MgmtPublicServiceClient, *grpc.ClientConn) { + + var clientDialOpts grpc.DialOption + if cert != "" && key != "" { + creds, err := credentials.NewServerTLSFromFile(cert, key) + if err != nil { + panic(err) + } + clientDialOpts = grpc.WithTransportCredentials(creds) + } else { + clientDialOpts = grpc.WithTransportCredentials(insecure.NewCredentials()) + } + + clientConn, err := grpc.Dial(server, clientDialOpts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxPayloadSize), grpc.MaxCallSendMsgSize(MaxPayloadSize))) + if err != nil { + return nil, nil + } + + return mgmtPB.NewMgmtPublicServiceClient(clientConn), clientConn +} + +func InitMgmtPrivateServiceClient(ctx context.Context, server string, cert string, key string) (mgmtPB.MgmtPrivateServiceClient, *grpc.ClientConn) { + + var clientDialOpts grpc.DialOption + if cert != "" && key != "" { + creds, err := credentials.NewServerTLSFromFile(cert, key) + if err != nil { + panic(err) + } + clientDialOpts = grpc.WithTransportCredentials(creds) + } else { + clientDialOpts = grpc.WithTransportCredentials(insecure.NewCredentials()) + } + + clientConn, err := grpc.Dial(server, clientDialOpts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxPayloadSize), grpc.MaxCallSendMsgSize(MaxPayloadSize))) + if err != nil { + return nil, nil + } + + return mgmtPB.NewMgmtPrivateServiceClient(clientConn), clientConn +} diff --git a/registry-plugin/go.mod b/registry-plugin/go.mod index 9e704f7..5e258dd 100644 --- a/registry-plugin/go.mod +++ b/registry-plugin/go.mod @@ -1,3 +1,21 @@ module registry-plugin -go 1.21 \ No newline at end of file +go 1.21 + +toolchain go1.21.3 + +require ( + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/instill-ai/protogen-go v0.3.3-alpha.0.20240308151517-4b0523c184d1 + google.golang.org/grpc v1.56.3 +) + +require ( + github.com/golang/protobuf v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/protobuf v1.30.0 // indirect +) diff --git a/registry-plugin/go.sum b/registry-plugin/go.sum index 2d29b57..f4de9b4 100644 --- a/registry-plugin/go.sum +++ b/registry-plugin/go.sum @@ -1,14 +1,127 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/instill-ai/protogen-go v0.3.3-alpha.0.20240308151517-4b0523c184d1 h1:8bhIcJZcUMKvZas2L0uyaVt/V+Tzw0OSR8GtdcFflMo= +github.com/instill-ai/protogen-go v0.3.3-alpha.0.20240308151517-4b0523c184d1/go.mod h1:jhEL0SauySMoPLVvx105DWyThju9sYTbsXIySVCArmM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/registry-plugin/interceptor.go b/registry-plugin/interceptor.go new file mode 100644 index 0000000..faf1c33 --- /dev/null +++ b/registry-plugin/interceptor.go @@ -0,0 +1,51 @@ +package main + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" + grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" +) + +// RecoveryInterceptor - panic handler +func recoveryInterceptorOpt() grpc_recovery.Option { + return grpc_recovery.WithRecoveryHandler(func(p interface{}) (err error) { + return status.Errorf(codes.Unknown, "panic triggered: %v", p) + }) +} + +// CustomInterceptor - append metadatas for unary +func unaryAppendMetadataInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, status.Error(codes.Internal, "can not extract metadata") + } + + newCtx := metadata.NewIncomingContext(ctx, md) + h, err := handler(newCtx, req) + + return h, err +} + +// CustomInterceptor - append metadatas for stream +func streamAppendMetadataInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + + md, ok := metadata.FromIncomingContext(stream.Context()) + if !ok { + return status.Error(codes.Internal, "can not extract metadata") + } + + newCtx := metadata.NewIncomingContext(stream.Context(), md) + wrapped := grpc_middleware.WrapServerStream(stream) + wrapped.WrappedContext = newCtx + + err := handler(srv, wrapped) + + return err +} diff --git a/registry-plugin/main.go b/registry-plugin/main.go index 7adb211..3f259ca 100644 --- a/registry-plugin/main.go +++ b/registry-plugin/main.go @@ -6,7 +6,12 @@ import ( "fmt" "io" "net/http" + "regexp" "strings" + + "google.golang.org/grpc/metadata" + + mgmtPB "github.com/instill-ai/protogen-go/core/mgmt/v1beta" ) // pluginName is the plugin name @@ -24,7 +29,7 @@ func (r registerer) RegisterHandlers(f func( f(string(r), r.registerHandlers) } -func (r registerer) registerHandlers(_ context.Context, extra map[string]interface{}, h http.Handler) (http.Handler, error) { +func (r registerer) registerHandlers(ctx context.Context, extra map[string]interface{}, h http.Handler) (http.Handler, error) { config, ok := extra[pluginName].(map[string]interface{}) if !ok { @@ -32,31 +37,122 @@ func (r registerer) registerHandlers(_ context.Context, extra map[string]interfa } hostport, _ := config["hostport"].(string) - prefix, _ := config["prefix"].(string) + + mgmtPublicClient, _ := InitMgmtPublicServiceClient(ctx, config["mgmt_public_hostport"].(string), "", "") + mgmtPrivateClient, _ := InitMgmtPrivateServiceClient(ctx, config["mgmt_private_hostport"].(string), "", "") return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - // If the URL path starts with "/v2/" (indicating the first handshake request to confirm registry V2 API), - // "/v2/prefix/" (before the registry prefix is applied), or "/prefix/v2/" (after the registry prefix is applied), + // If the URL path starts with "/v2/" (exactly /v2/ indicating the first handshake request to confirm registry V2 API), // it means that the request is intended for the Instill Artifact registry. In this case, the traffic is hijacked // and directly relayed to the registry. Otherwise, if the URL path does not match any of these patterns, // the traffic is passed through to the next handler. - if req.URL.Path != "/v2/" && - !strings.HasPrefix(req.URL.Path, fmt.Sprintf("/v2%s", prefix)) && - !strings.HasPrefix(req.URL.Path, fmt.Sprintf("%sv2/", prefix)) { + if !strings.HasPrefix(req.URL.Path, "/v2/") { h.ServeHTTP(w, req) return } + // Authenticate the user via docker login + var username, password string + if req.URL.Path == "/v2/" { + username, password, ok = req.BasicAuth() + if !ok { + // Challenge the user for basic authentication + w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) + writeStatusUnauthorized(req, w, "Instill AI user authentication failed") + return + } + + // Validate the api key and the namespace authorization + if !strings.HasPrefix(password, "instill_sk_") { + writeStatusUnauthorized(req, w, "Instill AI user authentication failed") + return + } + + ctx := metadata.AppendToOutgoingContext(ctx, "Authorization", fmt.Sprintf("Bearer %s", password)) + if resp, err := mgmtPublicClient.ValidateToken( + ctx, + &mgmtPB.ValidateTokenRequest{}, + ); err == nil { + userUID := resp.UserUid + // Check if the login username is the same with the user id retrieved from the token validation response + if resp, err := mgmtPrivateClient.LookUpUserAdmin( + ctx, + &mgmtPB.LookUpUserAdminRequest{ + Permalink: "users/" + userUID, + }, + ); err == nil { + if resp.User.Id != username { + fmt.Println(1) + writeStatusUnauthorized(req, w, "Instill AI user authentication failed") + return + } + } else { + logger.Error(err.Error()) + writeStatusInternalError(req, w) + return + } + + // To this point, if the req.URL.Path is "/v2/", return 200 OK to the client for login success + writeStatusOK(req, w) + return + } + + fmt.Println(2) + writeStatusUnauthorized(req, w, "Instill AI user authentication failed") + return + } + + // Docker image tag format: + // [registry]/[namespace]/[repository path]:[image tag] + // The namespace is the user uid or the organization uid + var namespace string + matches := regexp.MustCompile(`/v2/([^/]+).*`).FindStringSubmatch(req.URL.Path) + if len(matches) >= 2 { + namespace = matches[1] + } else { + writeStatusUnauthorized(req, w, + "Namespace is not found in the image name. Docker registry hosted in Instill Artifact has a format"+ + "[registry]/[namespace]/[repository path]:[image tag]."+ + "A namespace can be a user or organization ID.") + return + } + + // If the username and the namespace is not the same, + // check if the namespace is an organisation name where the user has the membership + if username != "" && namespace != username { + resp, err := mgmtPublicClient.ListUserMemberships( + ctx, + &mgmtPB.ListUserMembershipsRequest{ + Parent: fmt.Sprintf("users/%s", username), + }) + if err != nil { + fmt.Println(3) + writeStatusUnauthorized(req, w, "Instill AI user authentication failed") + return + } + isValid := false + for _, membership := range resp.Memberships { + if namespace == membership.Organization.Name && membership.State == mgmtPB.MembershipState_MEMBERSHIP_STATE_ACTIVE { + isValid = true + break + } + } + if !isValid { + fmt.Println(4) + writeStatusUnauthorized(req, w, "Instill AI user authentication failed") + return + } + } + req.URL.Scheme = "http" req.URL.Host = hostport - req.URL.Path = strings.TrimSuffix(prefix, "/") + strings.Replace(req.URL.Path, prefix, "/", 1) req.RequestURI = "" resp, err := http.DefaultClient.Do(req) if err != nil { logger.Error(err.Error()) - w.WriteHeader(http.StatusInternalServerError) + writeStatusInternalError(req, w) return } @@ -66,13 +162,55 @@ func (r registerer) registerHandlers(_ context.Context, extra map[string]interfa w.Header().Add(k, h) } } + w.WriteHeader(resp.StatusCode) + w.Header().Set("Content-Type", "application/json") io.Copy(w, resp.Body) resp.Body.Close() }), nil } +func writeStatusUnauthorized(req *http.Request, w http.ResponseWriter, error string) { + if req.ProtoMajor == 2 && strings.Contains(req.Header.Get("Content-Type"), "application/grpc") { + w.Header().Set("Content-Type", "application/grpc") + w.Header().Set("Trailer", "Grpc-Status") + w.Header().Add("Trailer", "Grpc-Message") + w.Header().Set("Grpc-Status", "16") + w.Header().Set("Grpc-Message", "Unauthenticated") + } else { + w.WriteHeader(http.StatusUnauthorized) + w.Header().Set("Content-Type", "application/json") + } + fmt.Fprintln(w, error) +} + +func writeStatusInternalError(req *http.Request, w http.ResponseWriter) { + if req.ProtoMajor == 2 && strings.Contains(req.Header.Get("Content-Type"), "application/grpc") { + w.Header().Set("Content-Type", "application/grpc") + w.Header().Set("Trailer", "Grpc-Status") + w.Header().Add("Trailer", "Grpc-Message") + w.Header().Set("Grpc-Status", "13") + w.Header().Set("Grpc-Message", "INTERNAL") + } else { + w.WriteHeader(http.StatusInternalServerError) + w.Header().Set("Content-Type", "application/json") + } +} + +func writeStatusOK(req *http.Request, w http.ResponseWriter) { + if req.ProtoMajor == 2 && strings.Contains(req.Header.Get("Content-Type"), "application/grpc") { + w.Header().Set("Content-Type", "application/grpc") + w.Header().Set("Trailer", "Grpc-Status") + w.Header().Add("Trailer", "Grpc-Message") + w.Header().Set("Grpc-Status", "0") + w.Header().Set("Grpc-Message", "OK") + } else { + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + } +} + func main() {} // This logger is replaced by the RegisterLogger method to load the one from KrakenD