Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

astore: Split out auth main.go #966

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
65 changes: 10 additions & 55 deletions astore/server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,16 @@ go_library(
importpath = "github.com/enfabrica/enkit/astore/server",
visibility = ["//visibility:private"],
deps = [
"//auth/common:go_default_library",
"//astore/rpc/astore:go_default_library",
"//auth/proto:go_default_library",
"//auth/server/assets:go_default_library", # keep
"//astore/server/astore:go_default_library",
"//auth/server/auth:go_default_library",
"//astore/server/configs:go_default_library", # keep
"//auth/server/credentials:go_default_library", # keep
"//auth/server/templates",
"//astore/server/configs:go_default_library",
"//auth/server/assets:go_default_library",
"//auth/server/credentials:go_default_library",
"//auth/server/templates:go_default_library",
"//lib/kflags:go_default_library",
"//lib/kflags/kcobra:go_default_library",
"//lib/kflags/kconfig:go_default_library",
"//lib/khttp/kassets:go_default_library",
"//lib/khttp/kcookie:go_default_library",
"//lib/logger:go_default_library",
"//lib/oauth:go_default_library",
"//lib/oauth/ogrpc:go_default_library",
Expand All @@ -37,60 +33,13 @@ go_library(
],
)

go_binary(
name = "server",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)

# Generate a .go file containing all the credentials supplied during the build.
go_embed_data(
name = "embedded-credentials",
srcs = glob(["credentials/**/*.flag*"]),
flatten = True,
package = "credentials",
visibility = ["//visibility:public"],
)

go_library(
name = "credentials",
srcs = [":embedded-credentials"],
importpath = "github.com/enfabrica/enkit/astore/server/credentials",
visibility = ["//visibility:public"],
)

# Generate a .go file containing all the configs supplied during the build.
go_embed_data(
name = "embedded-configs",
srcs = glob(["configs/**/*.config*"]),
flatten = True,
package = "configs",
visibility = ["//visibility:public"],
)

go_library(
name = "configs",
srcs = [":embedded-configs"],
importpath = "github.com/enfabrica/enkit/astore/server/configs",
visibility = ["//visibility:public"],
)

# Generate a .go file containing all the web assets.
go_embed_data(
name = "embedded-assets",
srcs = ["//auth/server/assets:css"] + glob(["assets/**"]),
flatten = True,
package = "assets",
visibility = ["//visibility:public"],
)

go_library(
name = "assets",
srcs = [":embedded-assets"],
importpath = "github.com/enfabrica/enkit/astore/server/assets",
visibility = ["//visibility:public"],
)

go_appengine_deploy(
name = "deploy",
config = "deploy/app.yaml",
Expand All @@ -102,3 +51,9 @@ go_appengine_deploy(
":server",
],
)

go_binary(
name = "server",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
File renamed without changes.
File renamed without changes
File renamed without changes
21 changes: 21 additions & 0 deletions astore/server/assets/credentials/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//extras:embed_data.bzl", "go_embed_data")

# Generate a .go file containing all the credentials supplied during the build.
go_embed_data(
name = "embedded-credentials",
srcs = glob(["**/*.flag*"]),
flatten = True,
package = "credentials",
visibility = ["//visibility:public"],
)

go_library(
name = "go_default_library",
srcs = [
"empty.go",
":embedded-credentials", # keep
],
importpath = "github.com/enfabrica/enkit/astore/server/assets/credentials",
visibility = ["//visibility:public"],
)
91 changes: 91 additions & 0 deletions astore/server/assets/credentials/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Credentials directory

There are 2 ways to provide credentials to the astore server:

1) Provide the credentials at run time. Use command line flags like `--credentials-file` to
specify the path of the file containing credentials.

2) Build the credentials into the binary before pushing it. Create a `.flag` file for each
flag you want to compile into the binary at build time.
For example, to build a default `credentials-file` into the binary, just store a `credentials-file.flag`
in this directory, and build the binary again with `bazel` or `bazelisk`.
The file has to be named after a flag name, with flag extension, and contains the raw value that
the flag expects.

For example, if the flag expects the path of a json file, and the flag is called `--signing-config`, you
need to create a `signing-config.flag` in this directory, with the desired json file.

Extra extensions are ignored, so if you prefer to call the file `signing-config.flag.json`, it is entirely
up to you.

# Recommended files

Before trying to create the files, make sure you have created a project:

1. Go to the [google cloud console](http://console.cloud.google.com)
2. Use the pull down menu in the very top navigation bar to the left of the search bar to open a popup to select a project.
3. Click "NEW PROJECT".

To automatically deploy an astore server, the following files need to be provided:

* bucket.flag - name of the GCS bucket to use. This is where the artifacts will be stored on GCS.
To create a bucket, go to: https://console.cloud.google.com/storage/create-bucket

* signing-config.flag.json - .json file containing the GCP key to use to generate signed URLs.
To create this file, you need to:

1. Create a service account by clicking "CREATE SERVICE ACCOUNT" [here](https://console.cloud.google.com/iam-admin/serviceaccounts).
2. Download the .json file with the key, and store it as signing-config.json.
3. Authorize the service account to have access to your bucket. Go on the [storage browser](https://console.cloud.google.com/storage/browser),
click on the newly created bucket, "PERMISSIONS" tab, "ADD" button, selecting the service account you create in point 1 as member
(you may need to cut and paste the full name, [email protected]), and then granting the "Storage Object Admin" privilege.

Without a signing-config file, all uploads and downloads will fail. If no credentials-config file is specified,
the server will fall back to use the credentials-file.

* secret-file.flag.json - .json file containing the secret identifying the application with the google oauth servers.
To create this file:

1. Go on http://developers.console.google.com, "Oauth Consent Screen", create an internal consent screen.
2. On the same console, go on "Credentials", click on "+ Create Credentials" at the top, select "Oauth Client ID",
pick "Web Application", configure the two URLs accordingly. For example, if you want to serve the authenticator
as "auth.startup.com", you'll need to specify "https://auth.startup.com/" in Authorized JavaScript origins, and
"https://auth.startup.com/e/" (note the appended "/e/", used internally by the server), as "Authorized redirect URIs".
3. Download the generated keys.

* token-encryption-key.flag.bin - this is a file generated with the `entoken` utility. Run:

bazelisk run //lib/token/cli:entoken -- symmetric generate -k /tmp/file.key
cp -f /tmp/file.key ./astore/server/credentials/token-encryption-key.flag.bin

* token-signing-key.flag.bin, and token-verifying-key.flag.bin - also generated with the `entoken` utility. Run:

bazelisk run //lib/token/cli:entoken -- signing generate -s /tmp/signing.key -f /tmp/verifying.key
cp -f /tmp/signing.key ./astore/server/credentials/token-signing-key.flag.bin
cp -f /tmp/verifying.key ./astore/server/credentials/token-verifying-key.flag.bin

* site-url.flag - this file contains the public URL users will use to reach the authentication server.
Visit [appengine custom domain console](https://console.cloud.google.com/appengine/settings/domains) to
configure your app to serve the desired domain.

If you bought your domains via google, you can then create subdomains by using [the domain admin page](http://domains.google.com).
Note that at time of writing (07/2020) there seems to be a bug in the console, by which subdomains like `auth.corp` cannot
be typed. Cut & paste works.

* credentials-file.flag.json (optional) - .json file containing the GCP key to use to authenticate with
GCS and datastore. This file is only necessary if you are running the server outside of google cloud.
In facts, when running in Google App Engine or GCP, credentials are automatically provided in the environment.

To generate this file, follow the same instructions to generate a signing-config file. It can be the same file,
although it's a generally a good idea to keep them separate.

* project-id-file.flag.json (optional) - file containing the project-id to use when accessing the datastore API.
This is only necessary if you are running the server outside of google cloud. You can see the project-id to
use by looking at the first column of `gcloud projects list`.

* cookie-domain.flag (optional) - contains a domain name, which will be used to set the Domain option in
authentication cookies, allowing those cookies to be shared within the domain. Due to how HTTP works,
cookie-domain should be a parent domain or sub-domain of site-url, otherwise the browser will reject
the option. As you authorize the authentication cookie to be shared within this domain, the auth server
also assumes that it is ok to redirect the user back to one of those host names at the end of the
authentication process.
3 changes: 3 additions & 0 deletions astore/server/assets/credentials/empty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package credentials is empty here because this package contains only embedded
// assets; having a source file here helps `go get -u ./...` to not error.
package credentials
File renamed without changes.
File renamed without changes
File renamed without changes.
25 changes: 25 additions & 0 deletions astore/server/assets/templates/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//bazel/qtc:defs.bzl", "qtpl_go_library")

qtpl_go_library(
name = "templates",
srcs = [
"list.qtpl",
"message.qtpl",
"struct.qtpl",
],
importpath = "github.com/enfabrica/enkit/astore/server/templates",
visibility = ["//visibility:public"],
deps = [
"//astore/rpc/astore:go_default_library",
"@com_github_dustin_go_humanize//:go_default_library",
],
)

go_library(
name = "go_default_library",
srcs = ["empty.go"],
embed = [":templates"], # keep
importpath = "github.com/enfabrica/enkit/astore/server/assets/templates",
visibility = ["//visibility:public"],
)
3 changes: 3 additions & 0 deletions astore/server/assets/templates/empty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package templates is empty here because this package contains only code from
// generated templates; an empty source file helps satisfy `go get -u ./...`.
package templates
44 changes: 44 additions & 0 deletions astore/server/assets/templates/list.qtpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% import (
"github.com/enfabrica/enkit/astore/rpc/astore"
"github.com/dustin/go-humanize"
"time"
"fmt"
) %}
{% code
type ListPage struct {
// The title of the page.
PageTitle string
// The path being downloaded by the user.
Path string
// The base URL to redirect to.
Base string

// The response from the RPC server.
List *astore.ListResponse
}
%}
{% code
func (lp *ListPage) DownloadURL(art *astore.Artifact) string {
return fmt.Sprintf("%s%s?u=%s", lp.Base, lp.Path, art.Uid)
}
%}
{% func (m *ListPage) Title() %}{%s m.PageTitle %}{% endfunc %}
{% func (m *ListPage) Body() %}
{% for _, art := range m.List.Artifact %}
<div class="mdl-cell mdl-cell--2-col"></div>

<div class="mdl-card mdl-shadow--2dp mdl-cell mdl-cell--8-col">
<div class="mdl-card__title mdl-grid--no-spacing mdl-card--expand">
<h2 class="mdl-card__title-text">{%s m.Path %} - {%s art.Architecture %}</h2>
</div>
<div class="mdl-card__supporting-text">
MD5: {%s fmt.Sprintf("%x", art.MD5) %}, Size: {%s humanize.Bytes(uint64(art.Size)) %}, Created: {%s time.Unix(0, art.Created).String() %}
</div>
<div class="mdl-card__actions mdl-card--border">
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" href="{%s m.DownloadURL(art) %}">DOWNLOAD</a>
</div>
</div>

<div class="mdl-cell mdl-cell--2-col"></div>
{% endfor %}
{% endfunc %}
29 changes: 29 additions & 0 deletions astore/server/assets/templates/message.qtpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% code
type MessagePage struct {
PageTitle string

ImageCSS string
Highlight string
Text string
}
%}
{% func (m *MessagePage) Title() %}{%s m.PageTitle %}{% endfunc %}
{% func (m *MessagePage) Body() %}
<div class="mdl-cell mdl-cell--2-col"></div>

<div class="mdl-card mdl-shadow--2dp mdl-cell mdl-cell--8-col">
<div class="mdl-card__title mdl-grid--no-spacing mdl-card--expand">
<div class="mdl-cell mdl-cell--3-col-tablet mdl-cell--12-col-phone">
<div class="avatar" id="{%s m.ImageCSS %}"></div>
</div>
<div class="mdl-cell mdl-cell--9-col-desktop mdl-cell--12-col-phone">
<div class="mdl-card__title-text">
<h2>{%s m.Highlight %}</h2>
</div>
<div class="mdl-card__supporting-text">{%s= m.Text %}</div>
</div>
</div>
</div>

<div class="mdl-cell mdl-cell--2-col"></div>
{% endfunc %}
28 changes: 28 additions & 0 deletions astore/server/assets/templates/struct.qtpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{% interface
Page {
Title()
Body()
}
%}
{% func PageTemplate(p Page) %}<!doctype html>
<!DOCTYPE html>
<html>
<head>
<title>{%= p.Title() %}</title>
<link rel="stylesheet" href="/material.min.css">
<script src="/material.min.js"></script>
<link rel="stylesheet" href="/material-icons.css">
<link rel="stylesheet" href="/site.css">
</head>

<body><div class="mdl-layout mdl-js-layout" width="100%">

<main class="mdl-layout__content">
<div class="mdl-grid">
{%= p.Body() %}
</div>
</main>

</div></body>
</html>
{% endfunc %}
File renamed without changes
Loading