Skip to content
Merged
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
112 changes: 73 additions & 39 deletions server/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package application
import (
"bufio"
"encoding/json"
"fmt"
"path"
"reflect"
"strings"
Expand Down Expand Up @@ -68,16 +67,21 @@ func NewServer(
}
}

// appRBACName formats fully qualified application name for RBAC check
func appRBACName(app appv1.Application) string {
return path.Join(git.NormalizeGitURL(app.Spec.Source.RepoURL), app.Name)
}

// List returns list of applications
func (s *Server) List(ctx context.Context, q *ApplicationQuery) (*appv1.ApplicationList, error) {
appList, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
newItems := make([]appv1.Application, 0)
for _, app := range appList.Items {
if s.enf.EnforceClaims(ctx.Value("claims"), "applications", "get", fmt.Sprintf("*/%s", app.Name)) {
newItems = append(newItems, app)
for _, a := range appList.Items {
if s.enf.EnforceClaims(ctx.Value("claims"), "applications", "get", appRBACName(a)) {
newItems = append(newItems, a)
}
}
appList.Items = newItems
Expand All @@ -86,7 +90,7 @@ func (s *Server) List(ctx context.Context, q *ApplicationQuery) (*appv1.Applicat

// Create creates an application
func (s *Server) Create(ctx context.Context, q *ApplicationCreateRequest) (*appv1.Application, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "create", fmt.Sprintf("*/%s", q.Application.Name)) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "create", appRBACName(q.Application)) {
return nil, grpc.ErrPermissionDenied
}
a := q.Application
Expand All @@ -103,7 +107,7 @@ func (s *Server) Create(ctx context.Context, q *ApplicationCreateRequest) (*appv
return nil, status.Errorf(codes.Internal, "unable to check existing application details: %v", err)
}
if q.Upsert != nil && *q.Upsert {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", fmt.Sprintf("*/%s", q.Application.Name)) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", appRBACName(a)) {
return nil, grpc.ErrPermissionDenied
}
existing.Spec = a.Spec
Expand All @@ -121,39 +125,39 @@ func (s *Server) Create(ctx context.Context, q *ApplicationCreateRequest) (*appv

// GetManifests returns application manifests
func (s *Server) GetManifests(ctx context.Context, q *ApplicationManifestQuery) (*repository.ManifestResponse, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/manifests", "get", fmt.Sprintf("*/%s", *q.Name)) {
return nil, grpc.ErrPermissionDenied
}
app, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
repo := s.getRepo(ctx, app.Spec.Source.RepoURL)
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/manifests", "get", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
repo := s.getRepo(ctx, a.Spec.Source.RepoURL)

conn, repoClient, err := s.repoClientset.NewRepositoryClient()
if err != nil {
return nil, err
}
defer util.Close(conn)
overrides := make([]*appv1.ComponentParameter, len(app.Spec.Source.ComponentParameterOverrides))
if app.Spec.Source.ComponentParameterOverrides != nil {
for i := range app.Spec.Source.ComponentParameterOverrides {
item := app.Spec.Source.ComponentParameterOverrides[i]
overrides := make([]*appv1.ComponentParameter, len(a.Spec.Source.ComponentParameterOverrides))
if a.Spec.Source.ComponentParameterOverrides != nil {
for i := range a.Spec.Source.ComponentParameterOverrides {
item := a.Spec.Source.ComponentParameterOverrides[i]
overrides[i] = &item
}
}

revision := app.Spec.Source.TargetRevision
revision := a.Spec.Source.TargetRevision
if q.Revision != "" {
revision = q.Revision
}
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &repository.ManifestRequest{
Repo: repo,
Environment: app.Spec.Source.Environment,
Path: app.Spec.Source.Path,
Environment: a.Spec.Source.Environment,
Path: a.Spec.Source.Path,
Revision: revision,
ComponentParameterOverrides: overrides,
AppLabel: app.Name,
AppLabel: a.Name,
})
if err != nil {
return nil, err
Expand All @@ -164,15 +168,23 @@ func (s *Server) GetManifests(ctx context.Context, q *ApplicationManifestQuery)

// Get returns an application by name
func (s *Server) Get(ctx context.Context, q *ApplicationQuery) (*appv1.Application, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "get", fmt.Sprintf("*/%s", *q.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "get", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
return s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
return a, nil
}

// ListResourceEvents returns a list of event resources
func (s *Server) ListResourceEvents(ctx context.Context, q *ApplicationResourceEventsQuery) (*v1.EventList, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/events", "get", fmt.Sprintf("*/%s", *q.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/events", "get", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
Expand All @@ -198,7 +210,7 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *ApplicationResourceE

// Update updates an application
func (s *Server) Update(ctx context.Context, q *ApplicationUpdateRequest) (*appv1.Application, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", fmt.Sprintf("*/%s", q.Application.Name)) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", appRBACName(*q.Application)) {
return nil, grpc.ErrPermissionDenied
}
a := q.Application
Expand All @@ -211,10 +223,14 @@ func (s *Server) Update(ctx context.Context, q *ApplicationUpdateRequest) (*appv

// UpdateSpec updates an application spec
func (s *Server) UpdateSpec(ctx context.Context, q *ApplicationUpdateSpecRequest) (*appv1.ApplicationSpec, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", fmt.Sprintf("*/%s", *q.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
err := s.validateApp(ctx, &q.Spec)
err = s.validateApp(ctx, &q.Spec)
if err != nil {
return nil, err
}
Expand All @@ -230,14 +246,15 @@ func (s *Server) UpdateSpec(ctx context.Context, q *ApplicationUpdateSpecRequest

// Delete removes an application and all associated resources
func (s *Server) Delete(ctx context.Context, q *ApplicationDeleteRequest) (*ApplicationResponse, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "delete", fmt.Sprintf("*/%s", *q.Name)) {
return nil, grpc.ErrPermissionDenied
}
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil && !apierr.IsNotFound(err) {
return nil, err
}

if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "delete", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}

if q.Cascade != nil && *q.Cascade != a.CascadedDeletion() {
a.SetCascadedDeletion(*q.Cascade)
patch, err := json.Marshal(map[string]interface{}{
Expand Down Expand Up @@ -271,15 +288,15 @@ func (s *Server) Watch(q *ApplicationQuery, ws ApplicationService_WatchServer) e
done := make(chan bool)
go func() {
for next := range w.ResultChan() {
app := *next.Object.(*appv1.Application)
if q.Name == nil || *q.Name == "" || *q.Name == app.Name {
if !s.enf.EnforceClaims(claims, "applications", "get", fmt.Sprintf("*/%s", app.Name)) {
a := *next.Object.(*appv1.Application)
if q.Name == nil || *q.Name == "" || *q.Name == a.Name {
if !s.enf.EnforceClaims(claims, "applications", "get", appRBACName(a)) {
// do not emit apps user does not have accessing
continue
}
err = ws.Send(&appv1.ApplicationWatchEvent{
Type: next.Type,
Application: app,
Application: a,
})
if err != nil {
log.Warnf("Unable to send stream message: %v", err)
Expand Down Expand Up @@ -405,9 +422,15 @@ func (s *Server) ensurePodBelongsToApp(applicationName string, podName, namespac
}

func (s *Server) DeletePod(ctx context.Context, q *ApplicationDeletePodRequest) (*ApplicationResponse, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/pods", "delete", fmt.Sprintf("*/%s", *q.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}

if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/pods", "delete", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}

config, namespace, err := s.getApplicationClusterConfig(*q.Name)
if err != nil {
return nil, err
Expand All @@ -428,8 +451,11 @@ func (s *Server) DeletePod(ctx context.Context, q *ApplicationDeletePodRequest)
}

func (s *Server) PodLogs(q *ApplicationPodLogsQuery, ws ApplicationService_PodLogsServer) error {
claims := ws.Context().Value("claims")
if !s.enf.EnforceClaims(claims, "applications/logs", "get", fmt.Sprintf("*/%s", *q.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return err
}
if !s.enf.EnforceClaims(ws.Context().Value("claims"), "applications/logs", "get", appRBACName(*a)) {
return grpc.ErrPermissionDenied
}
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
Expand Down Expand Up @@ -498,11 +524,11 @@ func (s *Server) PodLogs(q *ApplicationPodLogsQuery, ws ApplicationService_PodLo
}

func (s *Server) getApplicationDestination(ctx context.Context, name string) (string, string, error) {
app, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(name, metav1.GetOptions{})
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(name, metav1.GetOptions{})
if err != nil {
return "", "", err
}
server, namespace := app.Spec.Destination.Server, app.Spec.Destination.Namespace
server, namespace := a.Spec.Destination.Server, a.Spec.Destination.Namespace
return server, namespace, nil
}

Expand All @@ -517,7 +543,11 @@ func (s *Server) getRepo(ctx context.Context, repoURL string) *appv1.Repository

// Sync syncs an application to its target state
func (s *Server) Sync(ctx context.Context, syncReq *ApplicationSyncRequest) (*appv1.Application, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "sync", fmt.Sprintf("*/%s", *syncReq.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*syncReq.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "sync", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
return s.setAppOperation(ctx, *syncReq.Name, func(app *appv1.Application) (*appv1.Operation, error) {
Expand All @@ -532,7 +562,11 @@ func (s *Server) Sync(ctx context.Context, syncReq *ApplicationSyncRequest) (*ap
}

func (s *Server) Rollback(ctx context.Context, rollbackReq *ApplicationRollbackRequest) (*appv1.Application, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "rollback", fmt.Sprintf("*/%s", *rollbackReq.Name)) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*rollbackReq.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "rollback", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
return s.setAppOperation(ctx, *rollbackReq.Name, func(app *appv1.Application) (*appv1.Operation, error) {
Expand Down