Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement gRPC service for envoy ExtAuthz #4990

Merged
merged 7 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 55 additions & 16 deletions cmd/pipecd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,15 @@
)

type server struct {
pipedAPIPort int
webAPIPort int
httpPort int
apiPort int
adminPort int
staticDir string
cacheAddress string
gracePeriod time.Duration
pipedAPIPort int
webAPIPort int
httpPort int
apiPort int
adminPort int
envoyAuthzPort int
staticDir string
cacheAddress string
gracePeriod time.Duration

tls bool
certFile string
Expand All @@ -97,14 +98,15 @@
// NewServerCommand creates a new cobra command for executing api server.
func NewServerCommand() *cobra.Command {
s := &server{
pipedAPIPort: 9080,
webAPIPort: 9081,
httpPort: 9082,
apiPort: 9083,
adminPort: 9085,
staticDir: "web/static",
cacheAddress: "cache:6379",
gracePeriod: 30 * time.Second,
pipedAPIPort: 9080,
webAPIPort: 9081,
httpPort: 9082,
apiPort: 9083,
adminPort: 9085,
envoyAuthzPort: 9086,
staticDir: "web/static",
cacheAddress: "cache:6379",
gracePeriod: 30 * time.Second,

Check warning on line 109 in cmd/pipecd/server.go

View check run for this annotation

Codecov / codecov/patch

cmd/pipecd/server.go#L101-L109

Added lines #L101 - L109 were not covered by tests
}
cmd := &cobra.Command{
Use: "server",
Expand All @@ -117,6 +119,7 @@
cmd.Flags().IntVar(&s.httpPort, "http-port", s.httpPort, "The port number used to run a http server that serves incoming http requests such as auth callbacks or webhook events.")
cmd.Flags().IntVar(&s.apiPort, "api-port", s.apiPort, "The port number used to run a grpc server for external apis.")
cmd.Flags().IntVar(&s.adminPort, "admin-port", s.adminPort, "The port number used to run a HTTP server for admin tasks such as metrics, healthz.")
cmd.Flags().IntVar(&s.envoyAuthzPort, "envoy-authz-port", s.envoyAuthzPort, "The port number used to run a gRPC server that serves envoy ExtAuthz service.")

Check warning on line 122 in cmd/pipecd/server.go

View check run for this annotation

Codecov / codecov/patch

cmd/pipecd/server.go#L122

Added line #L122 was not covered by tests
cmd.Flags().StringVar(&s.staticDir, "static-dir", s.staticDir, "The directory where contains static assets.")
cmd.Flags().StringVar(&s.cacheAddress, "cache-address", s.cacheAddress, "The address to cache service.")
cmd.Flags().DurationVar(&s.gracePeriod, "grace-period", s.gracePeriod, "How long to wait for graceful shutdown.")
Expand Down Expand Up @@ -375,6 +378,42 @@
})
}

// Start a gRPC server for handling envoy ext_authz requests.
{
var (
verifier = pipedverifier.NewVerifier(
ctx,
cfg,
// These stores are used to handle request from piped over envoy ext_authz, thus the writer should be PipedWriter.
datastore.NewProjectStore(ds, datastore.PipedCommander),
datastore.NewPipedStore(ds, datastore.PipedCommander),
input.Logger,
)
service = grpcapi.NewEnvoyAuthorizationServer(verifier)
opts = []rpc.Option{
rpc.WithPort(s.envoyAuthzPort),
rpc.WithGracePeriod(s.gracePeriod),
rpc.WithLogger(input.Logger),
rpc.WithLogUnaryInterceptor(input.Logger),
}
)

if s.tls {
opts = append(opts, rpc.WithTLS(s.certFile, s.keyFile))
}
if s.enableGRPCReflection {
opts = append(opts, rpc.WithGRPCReflection())
}
if input.Flags.Metrics {
opts = append(opts, rpc.WithPrometheusUnaryInterceptor())
}

Check warning on line 409 in cmd/pipecd/server.go

View check run for this annotation

Codecov / codecov/patch

cmd/pipecd/server.go#L382-L409

Added lines #L382 - L409 were not covered by tests

server := rpc.NewServer(service, opts...)
group.Go(func() error {
return server.Run(ctx)
})

Check warning on line 414 in cmd/pipecd/server.go

View check run for this annotation

Codecov / codecov/patch

cmd/pipecd/server.go#L411-L414

Added lines #L411 - L414 were not covered by tests
}

// Wait until all components have finished.
// A terminating signal or a finish of any components
// could trigger the finish of server.
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.0
github.com/creasty/defaults v1.6.0
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f
github.com/envoyproxy/protoc-gen-validate v0.10.1
github.com/fsouza/fake-gcs-server v1.21.0
github.com/go-sql-driver/mysql v1.6.0
Expand All @@ -42,7 +43,7 @@ require (
github.com/slack-go/slack v0.12.2
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.1
github.com/stretchr/testify v1.8.3
go.uber.org/atomic v1.7.0
go.uber.org/zap v1.10.1-0.20190709142728-9a9fa7d4b5f0
golang.org/x/crypto v0.21.0
Expand Down Expand Up @@ -98,6 +99,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chzyer/readline v1.5.0 // indirect
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/cli v20.10.14+incompatible // indirect
Expand Down Expand Up @@ -155,7 +157,7 @@ require (
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/rs/xid v1.2.1 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
Expand Down
10 changes: 8 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
Expand Down Expand Up @@ -228,6 +230,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA=
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8=
github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
Expand Down Expand Up @@ -589,8 +593,9 @@ github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
Expand Down Expand Up @@ -658,8 +663,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
Expand Down
79 changes: 79 additions & 0 deletions pkg/app/server/grpcapi/envoy_ext_authz_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2024 The PipeCD Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package grpcapi
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the pipecd license header (refer other files)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I added this commit: 6ed9c7a.


import (
"context"
"errors"
"strings"

"github.com/pipe-cd/pipecd/pkg/app/server/pipedverifier"
"github.com/pipe-cd/pipecd/pkg/rpc"
"github.com/pipe-cd/pipecd/pkg/rpc/rpcauth"

authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

var (
_ authv3.AuthorizationServer = (*EnvoyAuthorizationServer)(nil)
_ rpc.Service = (*EnvoyAuthorizationServer)(nil)
)

type EnvoyAuthorizationServer struct {
authv3.UnimplementedAuthorizationServer

verifier *pipedverifier.Verifier
}

func NewEnvoyAuthorizationServer(verifier *pipedverifier.Verifier) *EnvoyAuthorizationServer {
return &EnvoyAuthorizationServer{
verifier: verifier,
}

Check warning on line 46 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L43-L46

Added lines #L43 - L46 were not covered by tests
}

// Register implements rpc.Service.
func (e *EnvoyAuthorizationServer) Register(server *grpc.Server) {
authv3.RegisterAuthorizationServer(server, e)

Check warning on line 51 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L50-L51

Added lines #L50 - L51 were not covered by tests
}

// Check implements authv3.AuthorizationServer.
func (e *EnvoyAuthorizationServer) Check(ctx context.Context, request *authv3.CheckRequest) (*authv3.CheckResponse, error) {
a, ok := request.GetAttributes().GetRequest().GetHttp().GetHeaders()["authorization"]
if !ok {
return &authv3.CheckResponse{Status: status.New(codes.Unauthenticated, "missing authorization header").Proto()}, nil
}

Check warning on line 59 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L55-L59

Added lines #L55 - L59 were not covered by tests

projectID, pipedID, pipedKey, err := e.parseAuthorizationHeader(a)
if err != nil {
return &authv3.CheckResponse{Status: status.New(codes.PermissionDenied, err.Error()).Proto()}, nil
}

Check warning on line 64 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L61-L64

Added lines #L61 - L64 were not covered by tests

if err := e.verifier.Verify(ctx, projectID, pipedID, pipedKey); err != nil {
return &authv3.CheckResponse{Status: status.New(codes.PermissionDenied, err.Error()).Proto()}, nil
}

Check warning on line 68 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L66-L68

Added lines #L66 - L68 were not covered by tests

return &authv3.CheckResponse{Status: status.New(codes.OK, "OK").Proto()}, nil

Check warning on line 70 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L70

Added line #L70 was not covered by tests
}

func (e *EnvoyAuthorizationServer) parseAuthorizationHeader(header string) (string, string, string, error) {
if !strings.HasPrefix(header, "Bearer ") {
return "", "", "", errors.New("invalid authorization header")
}

Check warning on line 76 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L73-L76

Added lines #L73 - L76 were not covered by tests

return rpcauth.ParsePipedToken(strings.TrimPrefix(header, "Bearer "))

Check warning on line 78 in pkg/app/server/grpcapi/envoy_ext_authz_api.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/server/grpcapi/envoy_ext_authz_api.go#L78

Added line #L78 was not covered by tests
}
5 changes: 5 additions & 0 deletions pkg/rpc/rpcauth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
return fmt.Sprintf("%s,%s,%s", projectID, pipedID, pipedKey)
}

// ParsePipedToken parses a piped token and returns projectID, pipedID, pipedKey.
func ParsePipedToken(token string) (projectID, pipedID, pipedKey string, err error) {
return parsePipedToken(token)

Check warning on line 57 in pkg/rpc/rpcauth/auth.go

View check run for this annotation

Codecov / codecov/patch

pkg/rpc/rpcauth/auth.go#L56-L57

Added lines #L56 - L57 were not covered by tests
}

func parsePipedToken(token string) (projectID, pipedID, pipedKey string, err error) {
parts := strings.Split(token, ",")
if len(parts) != 3 {
Expand Down
Loading