From f81786c311fd56676cdbdf690e3be1583254ad04 Mon Sep 17 00:00:00 2001 From: JoshuaWilkes <14214200+JoshuaWilkes@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:22:44 +0800 Subject: [PATCH] Add S3 bucket access to granted --- go.mod | 30 +-- go.sum | 70 +++--- pkg/assume/assume.go | 8 +- pkg/assume/awsresource.go | 202 ++++++++++++++++++ pkg/assume/entrypoint.go | 1 + pkg/granted/rds/rds.go | 20 +- .../accessrequesthook/accessrequesthook.go | 88 ++++---- 7 files changed, 321 insertions(+), 98 deletions(-) create mode 100644 pkg/assume/awsresource.go diff --git a/go.mod b/go.mod index df1062e4..417a1861 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/common-fate/common-fate v0.15.13 github.com/common-fate/glide-cli v0.6.0 github.com/common-fate/grab v1.3.0 - github.com/common-fate/sdk v1.45.1 + github.com/common-fate/sdk v1.50.0 github.com/common-fate/xid v1.0.0 github.com/fatih/color v1.16.0 github.com/hashicorp/yamux v0.1.1 @@ -69,15 +69,14 @@ require ( github.com/fatih/structtag v1.2.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/getkin/kin-openapi v0.107.0 // indirect - github.com/go-chi/chi/v5 v5.0.10 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-chi/chi/v5 v5.1.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.2 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/swag v0.22.3 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.4.0 // indirect - github.com/gorilla/schema v1.4.1 // indirect - github.com/gorilla/securecookie v1.1.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect @@ -100,23 +99,24 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/shopspring/decimal v1.2.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/twinj/uuid v0.0.0-20151029044442-89173bcdda19 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xtaci/smux v1.5.24 // indirect - github.com/zitadel/oidc/v2 v2.12.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + github.com/zitadel/logging v0.6.0 // indirect + github.com/zitadel/oidc/v3 v3.26.0 // indirect + github.com/zitadel/schema v1.3.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect ) require ( diff --git a/go.sum b/go.sum index 4ae946b8..74a47a6b 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= @@ -98,8 +100,8 @@ github.com/common-fate/grab v1.3.0 h1:vGNBMfhAVAWtrLuH1stnhL4LsDb73drhegC/060q+O github.com/common-fate/grab v1.3.0/go.mod h1:6zH8GckZGFrOKfZzL4Y/2OTvxwFeL6cDtsztM0GGC2Y= github.com/common-fate/iso8601 v1.1.0 h1:nrej9shsK1aB4IyOAjZl68xGk8yDuUxVwQjoDzxSK2c= github.com/common-fate/iso8601 v1.1.0/go.mod h1:DU4mvUEkkWZUUSJq2aCuNqM1luSb0Pwyb2dLzXS+img= -github.com/common-fate/sdk v1.45.1 h1:3G8/Ct/l5uiDRGElExKn7kMxViHqq60R5tVQx1uSzio= -github.com/common-fate/sdk v1.45.1/go.mod h1:Y7yRweNikBpi/LRYPRx+wl/mlOx1VQ9xapglkGKEdcM= +github.com/common-fate/sdk v1.50.0 h1:PXorjpbRAel4sCYt56UZFIc3Ecb1AzJ+aqjngJR4Y0o= +github.com/common-fate/sdk v1.50.0/go.mod h1:OrXhzB2Y1JSrKGHrb4qRmY+6MF2M3MFb+3edBnessXo= github.com/common-fate/session-manager-plugin v0.0.0-20240723053832-3d311db99016 h1:WObxQKT/BuR8HWKSGsJ6aQb/cdhvkenkb1KWXNyPWeE= github.com/common-fate/session-manager-plugin v0.0.0-20240723053832-3d311db99016/go.mod h1:glAZTUB+4Eg0JVLC3B/YEomJv6QHcNS3klJjw9HC5Y8= github.com/common-fate/updatecheck v0.3.5 h1:UGIKMnYwuHjbhhCaisLz1pNPg8Z1nXEoWcfqT+4LkAg= @@ -145,11 +147,13 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= +github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -170,27 +174,23 @@ github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGF github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/protobuf v1.3.1/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.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -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/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/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= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= -github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= @@ -318,8 +318,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= -github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE= @@ -368,14 +368,18 @@ github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY= github.com/xtaci/smux v1.5.24/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zitadel/oidc/v2 v2.12.0 h1:4aMTAy99/4pqNwrawEyJqhRb3yY3PtcDxnoDSryhpn4= -github.com/zitadel/oidc/v2 v2.12.0/go.mod h1:LrRav74IiThHGapQgCHZOUNtnqJG0tcZKHro/91rtLw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank= +github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= +github.com/zitadel/oidc/v3 v3.26.0 h1:BG3OUK+JpuKz7YHJIyUxL5Sl2JV6ePkG42UP4Xv3J2w= +github.com/zitadel/oidc/v3 v3.26.0/go.mod h1:Cx6AYPTJO5q2mjqF3jaknbKOUjpq1Xui0SYvVhkKuXU= +github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= +github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= @@ -401,7 +405,6 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQz golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -409,10 +412,10 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -436,6 +439,7 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -467,8 +471,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= @@ -485,8 +487,6 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/assume/assume.go b/pkg/assume/assume.go index 3b92e729..12a12432 100644 --- a/pkg/assume/assume.go +++ b/pkg/assume/assume.go @@ -168,11 +168,17 @@ func AssumeCommand(c *cli.Context) error { clio.Successf("Saved AWS profile as %s. You can use this profile with the AWS CLI using the '--profile' flags when running AWS commands.", saveProfileName) } + } else if activeRoleFlag && os.Getenv("GRANTED_SSO") == "true" { profile, err = SSOProfileFromEnv() if err != nil { return err } + } else if assumeFlags.Bool("aws-resources") { + profile, err = ResourceAccess(c) + if err != nil { + return err + } } else { var wg sync.WaitGroup @@ -618,7 +624,7 @@ func AssumeCommand(c *cli.Context) error { return nil } - if assumeFlags.Bool("sso") { + if assumeFlags.Bool("sso") || assumeFlags.Bool("aws-resources") { output := PrepareStringsForShellScript([]string{creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, "", region, sessionExpiration, "true", profile.SSOStartURL(), profile.AWSConfig.SSORoleName, profile.SSORegion(), profile.AWSConfig.SSOAccountID, ""}) fmt.Printf("GrantedAssume %s %s %s %s %s %s %s %s %s %s %s %s", output...) diff --git a/pkg/assume/awsresource.go b/pkg/assume/awsresource.go new file mode 100644 index 00000000..3251bae0 --- /dev/null +++ b/pkg/assume/awsresource.go @@ -0,0 +1,202 @@ +package assume + +import ( + "context" + "errors" + "time" + + "connectrpc.com/connect" + awsConfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/common-fate/clio" + "github.com/common-fate/grab" + "github.com/common-fate/granted/pkg/cfaws" + "github.com/common-fate/granted/pkg/hook/accessrequesthook" + cfflags "github.com/common-fate/granted/pkg/urfav_overrides" + "github.com/common-fate/sdk/config" + accessv1alpha1 "github.com/common-fate/sdk/gen/commonfate/access/v1alpha1" + "github.com/common-fate/sdk/service/access" + "github.com/common-fate/sdk/service/access/grants" + "github.com/mattn/go-runewidth" + sethRetry "github.com/sethvargo/go-retry" + "github.com/urfave/cli/v2" + "google.golang.org/protobuf/types/known/durationpb" +) + +func ResourceAccess(cliCtx *cli.Context) (*cfaws.Profile, error) { + ctx := cliCtx.Context + assumeFlags, err := cfflags.New("assumeFlags", GlobalFlags(), cliCtx) + if err != nil { + return nil, err + } + + cfg, err := config.LoadDefault(ctx) + if err != nil { + return nil, err + } + + err = cfg.Initialize(ctx, config.InitializeOpts{}) + if err != nil { + return nil, err + } + + client := access.NewFromConfig(cfg) + + entitlements, err := grab.AllPages(ctx, func(ctx context.Context, nextToken *string) ([]*accessv1alpha1.Entitlement, *string, error) { + res, err := client.QueryEntitlements(ctx, connect.NewRequest(&accessv1alpha1.QueryEntitlementsRequest{ + PageToken: grab.Value(nextToken), + TargetType: grab.Ptr("AWS::S3::Bucket"), + })) + if err != nil { + return nil, nil, err + } + return res.Msg.Entitlements, &res.Msg.NextPageToken, nil + }) + if err != nil { + return nil, err + } + + type Column struct { + Title string + Width int + } + cols := []Column{{Title: "S3 Bucket", Width: 60}, {Title: "Role", Width: 40}} + var s = make([]string, 0, len(cols)) + for _, col := range cols { + style := lipgloss.NewStyle().Width(col.Width).MaxWidth(col.Width).Inline(true) + renderedCell := style.Render(runewidth.Truncate(col.Title, col.Width, "…")) + s = append(s, lipgloss.NewStyle().Bold(true).Padding(0).Render(renderedCell)) + } + header := lipgloss.NewStyle().PaddingLeft(6).Render(lipgloss.JoinHorizontal(lipgloss.Left, s...)) + var options []huh.Option[*accessv1alpha1.Entitlement] + + for _, entitlement := range entitlements { + style := lipgloss.NewStyle().Width(cols[0].Width).MaxWidth(cols[0].Width).Inline(true) + target := lipgloss.NewStyle().Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Target.Display(), cols[0].Width, "…"))) + + style = lipgloss.NewStyle().Width(cols[1].Width).MaxWidth(cols[1].Width).Inline(true) + role := lipgloss.NewStyle().Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Role.Display(), cols[1].Width, "…"))) + + options = append(options, huh.Option[*accessv1alpha1.Entitlement]{ + Key: lipgloss.JoinHorizontal(lipgloss.Left, target, role), + Value: entitlement, + }) + } + + selector := huh.NewMultiSelect[*accessv1alpha1.Entitlement](). + Options(options...). + Title("Select the resources you need access to:"). + Description(header).WithTheme(huh.ThemeBase()) + err = selector.Run() + if err != nil { + return nil, err + } + + selected := selector.GetValue().([]*accessv1alpha1.Entitlement) + + // target = entitlement.Target.Eid.Display() + // role = entitlement.Role.Eid.Display() + + clio.Infow("selected", "value", selected) + + var duration *durationpb.Duration + if assumeFlags.String("duration") != "" { + d, err := time.ParseDuration(assumeFlags.String("duration")) + if err != nil { + return nil, err + } + duration = durationpb.New(d) + } + + input := accessrequesthook.NoEntitlementAccessInput{ + Entitlements: grab.Map(selected, func(t *accessv1alpha1.Entitlement) *accessv1alpha1.EntitlementInput { + return &accessv1alpha1.EntitlementInput{ + Target: &accessv1alpha1.Specifier{ + Specify: &accessv1alpha1.Specifier_Eid{ + Eid: t.Target.Eid, + }, + }, + Role: &accessv1alpha1.Specifier{ + Specify: &accessv1alpha1.Specifier_Eid{ + Eid: t.Role.Eid, + }, + }, + } + }), + Reason: assumeFlags.String("reason"), + Duration: duration, + Confirm: assumeFlags.Bool("confirm"), + Wait: assumeFlags.Bool("wait"), + StartTime: time.Now(), + } + hook := accessrequesthook.Hook{} + retry, result, err := hook.NoEntitlementAccess(ctx, cfg, input) + if err != nil { + return nil, err + } + + retryDuration := time.Minute * 1 + if assumeFlags.Bool("wait") { + //if wait is specified, increase the timeout to 15 minutes. + retryDuration = time.Minute * 15 + } + + if retry { + // reset the start time for the timer (otherwise it shows 2s, 7s, 12s etc) + input.StartTime = time.Now() + + b := sethRetry.NewConstant(5 * time.Second) + b = sethRetry.WithMaxDuration(retryDuration, b) + err = sethRetry.Do(ctx, b, func(ctx context.Context) (err error) { + + //also proactively check if request has been approved and attempt to activate + result, err = hook.RetryNoEntitlementAccess(ctx, cfg, input) + if err != nil { + + return sethRetry.RetryableError(err) + } + + return nil + }) + if err != nil { + return nil, err + } + + } + + clio.Info("Grant is activated") + + if result == nil || len(result.Grants) == 0 { + return nil, errors.New("could not load grant from Common Fate") + } + + firstGrant := result.Grants[0] + + grantsClient := grants.NewFromConfig(cfg) + + res, err := grantsClient.GetGrantOutput(ctx, connect.NewRequest(&accessv1alpha1.GetGrantOutputRequest{ + Id: firstGrant.Grant.Id, + })) + if err != nil { + return nil, err + } + dynRole := res.Msg.GetOutputAwsDynamicRole() + if dynRole == nil { + return nil, errors.New("expected grant output to be dynamic role") + } + + p := &cfaws.Profile{ + Name: dynRole.Id, + ProfileType: "AWS_SSO", + AWSConfig: awsConfig.SharedConfig{ + SSOAccountID: dynRole.AccountId, + SSORoleName: dynRole.SsoRoleName, + SSORegion: dynRole.SsoRegion, + SSOStartURL: dynRole.SsoStartUrl, + }, + Initialised: true, + } + + return p, nil +} diff --git a/pkg/assume/entrypoint.go b/pkg/assume/entrypoint.go index b18636d2..8b006dfe 100644 --- a/pkg/assume/entrypoint.go +++ b/pkg/assume/entrypoint.go @@ -55,6 +55,7 @@ func GlobalFlags() []cli.Flag { &cli.BoolFlag{Name: "confirm", Aliases: []string{"y"}, Usage: "Skip confirmation prompts for access requests"}, &cli.BoolFlag{Name: "wait", Usage: "When using Granted with Common Fate the assume will halt while waiting for the access request to be approved."}, &cli.BoolFlag{Name: "no-cache", Usage: "Disables caching of session credentials and forces a refresh", EnvVars: []string{"GRANTED_NO_CACHE"}}, + &cli.BoolFlag{Name: "aws-resources", Usage: "Access Specific resources in an AWS account"}, } } diff --git a/pkg/granted/rds/rds.go b/pkg/granted/rds/rds.go index 1104b311..281c88a3 100644 --- a/pkg/granted/rds/rds.go +++ b/pkg/granted/rds/rds.go @@ -119,10 +119,10 @@ var proxyCommand = cli.Command{ for _, entitlement := range entitlements { style := lipgloss.NewStyle().Width(cols[0].Width).MaxWidth(cols[0].Width).Inline(true) - target := lipgloss.NewStyle().Bold(true).Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Target.Display(), cols[0].Width, "…"))) + target := lipgloss.NewStyle().Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Target.Display(), cols[0].Width, "…"))) style = lipgloss.NewStyle().Width(cols[1].Width).MaxWidth(cols[1].Width).Inline(true) - role := lipgloss.NewStyle().Bold(true).Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Role.Display(), cols[1].Width, "…"))) + role := lipgloss.NewStyle().Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Role.Display(), cols[1].Width, "…"))) options = append(options, huh.Option[*accessv1alpha1.Entitlement]{ Key: lipgloss.JoinHorizontal(lipgloss.Left, target, role), @@ -152,8 +152,20 @@ var proxyCommand = cli.Command{ } input := accessrequesthook.NoEntitlementAccessInput{ - Target: target, - Role: role, + Entitlements: []*accessv1alpha1.EntitlementInput{ + { + Target: &accessv1alpha1.Specifier{ + Specify: &accessv1alpha1.Specifier_Lookup{ + Lookup: target, + }, + }, + Role: &accessv1alpha1.Specifier{ + Specify: &accessv1alpha1.Specifier_Lookup{ + Lookup: role, + }, + }, + }, + }, Reason: c.String("reason"), Duration: duration, Confirm: c.Bool("confirm"), diff --git a/pkg/hook/accessrequesthook/accessrequesthook.go b/pkg/hook/accessrequesthook/accessrequesthook.go index 6226e066..0eca043d 100644 --- a/pkg/hook/accessrequesthook/accessrequesthook.go +++ b/pkg/hook/accessrequesthook/accessrequesthook.go @@ -53,8 +53,16 @@ func (h Hook) NoAccess(ctx context.Context, input NoAccessInput) (retry bool, er clio.Infof("You don't currently have access to %s, checking if we can request access...\t[target=%s, role=%s, url=%s]", input.Profile.Name, target, role, cfg.AccessURL) retry, _, err = h.NoEntitlementAccess(ctx, cfg, NoEntitlementAccessInput{ - Target: target.String(), - Role: role, + Entitlements: []*accessv1alpha1.EntitlementInput{ + { + Target: target.ToSpecifier(), + Role: &accessv1alpha1.Specifier{ + Specify: &accessv1alpha1.Specifier_Lookup{ + Lookup: role, + }, + }, + }, + }, Reason: input.Reason, Duration: input.Duration, Confirm: input.Confirm, @@ -65,13 +73,12 @@ func (h Hook) NoAccess(ctx context.Context, input NoAccessInput) (retry bool, er } type NoEntitlementAccessInput struct { - Target string - Role string - Reason string - Duration *durationpb.Duration - Confirm bool - Wait bool - StartTime time.Time + Entitlements []*accessv1alpha1.EntitlementInput + Reason string + Duration *durationpb.Duration + Confirm bool + Wait bool + StartTime time.Time } func (h Hook) NoEntitlementAccess(ctx context.Context, cfg *config.Context, input NoEntitlementAccessInput) (retry bool, result *accessv1alpha1.BatchEnsureResponse, err error) { @@ -83,22 +90,12 @@ func (h Hook) NoEntitlementAccess(ctx context.Context, cfg *config.Context, inpu accessclient := access.NewFromConfig(cfg) + for i := range input.Entitlements { + input.Entitlements[i].Duration = input.Duration + } + req := accessv1alpha1.BatchEnsureRequest{ - Entitlements: []*accessv1alpha1.EntitlementInput{ - { - Target: &accessv1alpha1.Specifier{ - Specify: &accessv1alpha1.Specifier_Lookup{ - Lookup: input.Target, - }, - }, - Role: &accessv1alpha1.Specifier{ - Specify: &accessv1alpha1.Specifier_Lookup{ - Lookup: input.Role, - }, - }, - Duration: input.Duration, - }, - }, + Entitlements: input.Entitlements, Justification: &accessv1alpha1.Justification{}, } @@ -125,9 +122,17 @@ func (h Hook) NoEntitlementAccess(ctx context.Context, cfg *config.Context, inpu if err != nil { return false, nil, err } + if !hasChanges { - if result != nil && len(result.Grants) == 1 && result.Grants[0].Grant.Status == accessv1alpha1.GrantStatus_GRANT_STATUS_ACTIVE { - return false, result, nil + if result != nil { + allGrantsActive := true + for _, grant := range result.Grants { + if grant.Grant.Status != accessv1alpha1.GrantStatus_GRANT_STATUS_ACTIVE { + allGrantsActive = false + break + } + } + return !allGrantsActive, result, nil } if input.Wait { return true, result, nil @@ -271,8 +276,16 @@ func (h Hook) RetryAccess(ctx context.Context, input NoAccessInput) error { target := eid.New("AWS::Account", input.Profile.AWSConfig.SSOAccountID) role := input.Profile.AWSConfig.SSORoleName _, err = h.RetryNoEntitlementAccess(ctx, cfg, NoEntitlementAccessInput{ - Target: target.String(), - Role: role, + Entitlements: []*accessv1alpha1.EntitlementInput{ + { + Target: target.ToSpecifier(), + Role: &accessv1alpha1.Specifier{ + Specify: &accessv1alpha1.Specifier_Lookup{ + Lookup: role, + }, + }, + }, + }, Reason: input.Reason, Duration: input.Duration, Confirm: input.Confirm, @@ -283,23 +296,12 @@ func (h Hook) RetryAccess(ctx context.Context, input NoAccessInput) error { } func (h Hook) RetryNoEntitlementAccess(ctx context.Context, cfg *config.Context, input NoEntitlementAccessInput) (result *accessv1alpha1.BatchEnsureResponse, err error) { + for i := range input.Entitlements { + input.Entitlements[i].Duration = input.Duration + } req := accessv1alpha1.BatchEnsureRequest{ - Entitlements: []*accessv1alpha1.EntitlementInput{ - { - Target: &accessv1alpha1.Specifier{ - Specify: &accessv1alpha1.Specifier_Lookup{ - Lookup: input.Target, - }, - }, - Role: &accessv1alpha1.Specifier{ - Specify: &accessv1alpha1.Specifier_Lookup{ - Lookup: input.Role, - }, - }, - Duration: input.Duration, - }, - }, + Entitlements: input.Entitlements, Justification: &accessv1alpha1.Justification{}, } accessclient := access.NewFromConfig(cfg)