Created
March 29, 2022 23:40
-
-
Save salrashid123/41e4576b7ef44c51ad9f1bab12210a22 to your computer and use it in GitHub Desktop.
SignedURL, SignedJWT and SignBlob on Cloud Run Cloud Functions, GCE, GKE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
/* | |
Issue self-signed JWTs signBlob on Cloud Run, Cloud Functions, GCE, GKE | |
Assume the environment is running as `your_svc_account@project_id.iam.gserviceaccount.com ` | |
## first enable "self-impersonation" | |
] | |
gcloud iam service-accounts add-iam-policy-binding \ | |
your_svc_account@project_id.iam.gserviceaccount.com \ | |
--member=serviceAccount:your_svc_account@project_id.iam.gserviceaccount.com \ | |
--role=roles/iam.serviceAccountTokenCreator | |
# build and deploy (for cloud run) | |
docker build -t gcr.io/project_id/jwt . | |
docker push gcr.io/project_id/jwt | |
gcloud run deploy tok --image gcr.io/project_id/jwt \ | |
--service-account your_svc_account@project_id.iam.gserviceaccount.com \ | |
--allow-unauthenticated --region us-central1 --platform=managed | |
for SignedUrl, | |
see https://blog.salrashid.dev/articles/2021/cloud_sdk_missing_manual/gcs_signedurl/ | |
==================== | |
-- Dockerfile | |
FROM golang:1.17 as build | |
ENV GO111MODULE=on | |
WORKDIR /app | |
COPY . . | |
RUN go mod download | |
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build server.go | |
FROM gcr.io/distroless/base | |
COPY --from=build /app/server / | |
EXPOSE 8080 | |
ENTRYPOINT ["/server"] | |
*/ | |
import ( | |
"context" | |
"encoding/base64" | |
"encoding/json" | |
"fmt" | |
"log" | |
"net/http" | |
"time" | |
credentials "cloud.google.com/go/iam/credentials/apiv1" | |
"golang.org/x/net/http2" | |
credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1" | |
) | |
var () | |
type claimSet struct { | |
Aud string `json:"aud"` | |
Exp int64 `json:"exp"` | |
Iss string `json:"iss"` | |
Iat int64 `json:"iat"` | |
Sub string `json:"sub"` | |
Email string `json:"email"` | |
} | |
const ( | |
defaultAudience = "https://foo.bar" | |
svcAccountEmail = "[email protected]" | |
) | |
func fronthandler(w http.ResponseWriter, r *http.Request) { | |
fmt.Printf("/ called") | |
fmt.Fprint(w, "ok") | |
} | |
func jwthandler(w http.ResponseWriter, r *http.Request) { | |
ctx := context.Background() | |
c, err := credentials.NewIamCredentialsClient(ctx) | |
if err != nil { | |
fmt.Printf("%v", err) | |
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | |
return | |
} | |
defer c.Close() | |
p := &claimSet{ | |
Exp: time.Now().Add(time.Second * 30).Unix(), | |
Aud: defaultAudience, | |
Iss: svcAccountEmail, | |
Iat: time.Now().Unix(), | |
Sub: svcAccountEmail, | |
Email: svcAccountEmail, | |
} | |
pstr, err := json.Marshal(p) | |
if err != nil { | |
fmt.Printf("%v", err) | |
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | |
return | |
} | |
req := &credentialspb.SignJwtRequest{ | |
Name: fmt.Sprintf("projects/-/serviceAccounts/%s", svcAccountEmail), | |
Delegates: []string{}, | |
Payload: string(pstr), | |
} | |
resp, err := c.SignJwt(ctx, req) | |
if err != nil { | |
fmt.Printf("%v", err) | |
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | |
return | |
} | |
fmt.Printf("Signed JWT: %s\n", resp.SignedJwt) | |
fmt.Fprint(w, resp.SignedJwt) | |
} | |
func signhandler(w http.ResponseWriter, r *http.Request) { | |
ctx := context.Background() | |
c, err := credentials.NewIamCredentialsClient(ctx) | |
if err != nil { | |
fmt.Printf("%v", err) | |
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | |
return | |
} | |
defer c.Close() | |
sreq := &credentialspb.SignBlobRequest{ | |
Name: fmt.Sprintf("projects/-/serviceAccounts/%s", svcAccountEmail), | |
Delegates: []string{}, | |
Payload: []byte("foo"), | |
} | |
sresp, err := c.SignBlob(ctx, sreq) | |
if err != nil { | |
fmt.Printf("%v", err) | |
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | |
return | |
} | |
fmt.Printf("SignedBlob: %s\n", base64.StdEncoding.EncodeToString(sresp.SignedBlob)) | |
fmt.Fprint(w, base64.StdEncoding.EncodeToString(sresp.SignedBlob)) | |
} | |
func main() { | |
http.HandleFunc("/", fronthandler) | |
http.HandleFunc("/jwt", jwthandler) | |
http.HandleFunc("/sign", signhandler) | |
server := &http.Server{ | |
Addr: ":8080", | |
} | |
http2.ConfigureServer(server, &http2.Server{}) | |
log.Println("Starting Server..") | |
err := server.ListenAndServe() | |
log.Fatalf("Unable to start Server %v", err) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment