diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..e981162 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,61 @@ +--- +name: ci +on: push + +jobs: + lint: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: latest + test: + name: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + - run: go test -v ./... -covermode=atomic -coverprofile=coverage.out + - uses: codecov/codecov-action@v3 + with: + files: coverage.out + docker: + name: docker + runs-on: ubuntu-latest + needs: + - lint + - test + steps: + - uses: actions/checkout@v3 + - uses: docker/setup-qemu-action@v2 + - uses: docker/setup-buildx-action@v2 + - uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/metadata-action@v4 + id: meta + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + - uses: docker/build-push-action@v4 + with: + file: "Dockerfile" + context: . + platforms: linux/amd64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 4ec15a9..d168900 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:latest AS build +FROM golang:1.21 AS build WORKDIR /app diff --git a/go.mod b/go.mod index c24a1f8..6e9e406 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module gitlab.snapp.ir/snappcloud/hubble-middleware -go 1.19 +go 1.21 require ( github.com/golang-jwt/jwt/v4 v4.2.0 diff --git a/go.sum b/go.sum index 11359cd..f5f0b02 100644 --- a/go.sum +++ b/go.sum @@ -169,6 +169,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -315,7 +316,9 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/openshift/api v0.0.0-20221121222131-004dbc33dd4f h1:b0LA7hYl5LiAsXsNuzvgyzWmFQwFs0bhBN9M0dICZWM= github.com/openshift/api v0.0.0-20221121222131-004dbc33dd4f/go.mod h1:OW9hi5XDXOQWm/kRqUww6RVxZSf0nqrS4heerSmHBC4= github.com/openshift/client-go v0.0.0-20221107163225-3335a34a1d24 h1:V3J5k9LqJJpA2D8YOoJI8+Hr14mXauYR3uTI2/Foc+w= @@ -374,6 +377,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= diff --git a/internal/hubble-middleware/handler/project.go b/internal/hubble-middleware/handler/project.go index 3cf53e6..ea26bc4 100644 --- a/internal/hubble-middleware/handler/project.go +++ b/internal/hubble-middleware/handler/project.go @@ -4,8 +4,8 @@ import ( "context" "gitlab.snapp.ir/snappcloud/hubble-middleware/internal/auth" "net/http" + "slices" - "github.com/golang-jwt/jwt/v4" "github.com/labstack/echo/v4" "github.com/labstack/gommon/log" "github.com/sirupsen/logrus" @@ -13,6 +13,7 @@ import ( "k8s.io/client-go/rest" projectv1 "github.com/openshift/client-go/project/clientset/versioned/typed/project/v1" + groupv1 "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -20,12 +21,6 @@ type ( ProjectHandler struct { k8sClusterConfig *rest.Config } - - jwtCustomClaims struct { - jwt.Claims - - Username string `json:"username"` - } ) func NewProject(k8s *rest.Config) *ProjectHandler { @@ -39,7 +34,13 @@ func (h *ProjectHandler) Get(c echo.Context) error { return echo.ErrUnauthorized } - projects, err := h.getProjects(user.Username) + groups, err := h.getUserGroups(user.Username) + if err != nil { + log.Errorf("Get Groups Error: %s", err) + return echo.ErrInternalServerError + } + + projects, err := h.getUserProjects(user.Username, groups) if err != nil { log.Errorf("Get Projects Error: %s", err) return echo.ErrInternalServerError @@ -51,8 +52,13 @@ func (h *ProjectHandler) Get(c echo.Context) error { }) } -func (h *ProjectHandler) getProjects(username string) ([]string, error) { +func (h *ProjectHandler) getUserProjects(username string, groups []string) ([]string, error) { h.k8sClusterConfig.Impersonate.UserName = username + + if len(groups) > 0 { + h.k8sClusterConfig.Impersonate.Groups = groups + } + projectClientset, err := projectv1.NewForConfig(h.k8sClusterConfig) if err != nil { logrus.Error(err) @@ -72,3 +78,25 @@ func (h *ProjectHandler) getProjects(username string) ([]string, error) { return projects, err } + +func (h *ProjectHandler) getUserGroups(username string) ([]string, error) { + groupClientset, err := groupv1.NewForConfig(h.k8sClusterConfig) + if err != nil { + logrus.Error(err) + return nil, err + } + + res, err := groupClientset.Groups().List(context.Background(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + + groups := []string{} + for _, item := range res.Items { + if slices.Contains(item.Users, username) { + groups = append(groups, item.ObjectMeta.Name) + } + } + + return groups, err +}