Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Created March 29, 2022 23:40
Show Gist options
  • Save salrashid123/41e4576b7ef44c51ad9f1bab12210a22 to your computer and use it in GitHub Desktop.
Save salrashid123/41e4576b7ef44c51ad9f1bab12210a22 to your computer and use it in GitHub Desktop.
SignedURL, SignedJWT and SignBlob on Cloud Run Cloud Functions, GCE, GKE
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