Skip to content

Commit 7d23ba9

Browse files
authored
Merge pull request #460 from ampproject/master
Snapshot release v4
2 parents bf061be + da8a000 commit 7d23ba9

File tree

254 files changed

+44858
-10960
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

254 files changed

+44858
-10960
lines changed

.travis.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
# https://docs.travis-ci.com/user/languages/go/
22
language: go
3-
go: ["1.10"]
3+
4+
# Use ".x" to ask gimme to choose latest stable minor version of each Go
5+
# release: https://github.com/travis-ci/gimme
6+
go:
7+
- 1.11.x
8+
- 1.12.x
9+
- 1.13.x
10+
- 1.14.x
11+
12+
env:
13+
# Necessary for Go 1.11 and 1.12, so they'll respect the version constraints
14+
# in go.mod.
15+
- GO111MODULE=on

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@
187187
same "printed page" as the copyright notice for easier
188188
identification within third-party archives.
189189

190-
Copyright 2018 Google LLC
190+
Copyright [yyyy] [name of copyright owner]
191191

192192
Licensed under the Apache License, Version 2.0 (the "License");
193193
you may not use this file except in compliance with the License.

README.md

Lines changed: 106 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,29 @@ own and can obtain certificates for.
3434
1. Install Go version 1.10 or higher. Optionally, set
3535
[$GOPATH](https://github.com/golang/go/wiki/GOPATH) to something (default
3636
is `~/go`) and/or add `$GOPATH/bin` to `$PATH`.
37-
2. `go get -u -mod=vendor github.com/ampproject/amppackager/cmd/amppkg`
38-
39-
Optionally, move the built `~/go/bin/amppkg` wherever you like.
40-
3. Create a file `amppkg.toml`. A minimal config looks like this:
37+
1. Get amppackager.
38+
39+
Check your Go version by running `go version`.
40+
41+
For Go 1.14 and higher versions run:
42+
43+
```
44+
go get -u github.com/ampproject/amppackager/cmd/amppkg
45+
```
46+
47+
For Go 1.13 and earlier versions run:
48+
49+
```
50+
go get -u -mod=vendor github.com/ampproject/amppackager/cmd/amppkg
51+
```
52+
53+
1. Optionally, move the built `~/go/bin/amppkg` wherever you like.
54+
1. Prepare a temporary certificate and private key pair to use for signing the
55+
exchange when testing your config. Follow WICG
56+
[instructions](https://github.com/WICG/webpackage/tree/master/go/signedexchange#creating-our-first-signed-exchange)
57+
to ensure compliance with the [WICG certificate
58+
requirements](https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cross-origin-cert-req).
59+
1. Create a file `amppkg.toml`. A minimal config looks like this:
4160
```
4261
LocalOnly = true
4362
CertFile = 'path/to/fullchain.pem'
@@ -49,7 +68,7 @@ own and can obtain certificates for.
4968
Domain = "amppackageexample.com"
5069
```
5170
More details can be found in [amppkg.example.toml](amppkg.example.toml).
52-
4. `amppkg -development`
71+
1. `amppkg -development`
5372
5473
If `amppkg.toml` is not in the current working directory, pass
5574
`-config=/path/to/amppkg.toml`.
@@ -61,12 +80,17 @@ container.
6180
6281
#### Test your config
6382
64-
1. Run Chrome with the following commandline flags:
83+
1. Run Chrome with the following command line flags:
6584
```
66-
--user-data-dir=/tmp/udd
67-
--ignore-certificate-errors-spki-list=$(openssl x509 -pubkey -noout -in path/to/fullchain.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)
68-
--enable-features=SignedHTTPExchange
69-
'data:text/html,<a href="https://localhost:8080/priv/doc/https://amppackageexample.com/">click me'
85+
alias chrome = [FULL PATH TO CHROME BINARY]
86+
PATH_TO_FULLCHAIN_PEM = [FULL PATH TO fullchain.pem]
87+
chrome --user-data-dir=/tmp/udd\
88+
--ignore-certificate-errors-spki-list=$(\
89+
openssl x509 -pubkey -noout -in $PATH_TO_FULLCHAIN_PEM |\
90+
openssl pkey -pubin -outform der |\
91+
openssl dgst -sha256 -binary | base64)\
92+
--enable-features=SignedHTTPExchange\
93+
'data:text/html,<a href="https://localhost:8080/priv/doc/https://amppackageexample.com/">click me'
7094
```
7195
2. Open DevTools. Check 'Preserve log'.
7296
3. Click the `click me` link.
@@ -148,13 +172,15 @@ You may also want to:
148172
before publication, or with a regular audit of a sample of documents. The
149173
[transforms](transformer/) are designed to work on valid AMP pages, and
150174
may break invalid AMP in small ways.
175+
4. Setup
176+
[monitoring](#monitoring-amppackager-in-production-via-its-prometheus-endpoints)
177+
of `amppackager` and related requests to AMP document server.
151178
152179
Once you've done the above, you should be able to test by launching Chrome
153-
without any comamndline flags; just make sure
154-
chrome://flags/#enable-signed-http-exchange is enabled. To test by visiting the
155-
packager URL directly, first add a Chrome extension to send an
156-
`AMP-Cache-Transform: any` request header. Otherwise, follow the above
157-
"Demonstrate privacy-preserving prefetch" instructions.
180+
without any command line flags. To test by visiting the packager URL directly,
181+
first add a Chrome extension to send an `AMP-Cache-Transform: any` request
182+
header. Otherwise, follow the above "Demonstrate privacy-preserving prefetch"
183+
instructions.
158184
159185
##### Security Considerations
160186
@@ -175,8 +201,9 @@ that:
175201
176202
It is possible to test an otherwise fully production configuration without
177203
obtaining a certificate with the `CanSignHttpExchanges` extension. `amppkg`
178-
still needs to perform OCSP verification, so the Issuer CA must be valid (i.e. no
179-
self-signed certificates). e.g. You can use a certificate from [Let's Encrypt](https://letsencrypt.org/).
204+
still needs to perform OCSP verification, so the Issuer CA must be valid (i.e.
205+
no self-signed certificates). e.g. You can use a certificate from [Let's
206+
Encrypt](https://letsencrypt.org/).
180207
181208
Running `amppkg` with the `-invalidcert` flag will skip the check for
182209
`CanSignHttpExchanges`. This flag is not necessary when using the
@@ -204,8 +231,9 @@ eligible for use in the AMP viewer in other browsers.
204231
205232
### Limitations
206233
207-
Currently, the packager will refuse to sign any AMP documents larger than 4 MB.
208-
Patches that allow for streamed signing are welcome.
234+
Currently, the packager will refuse to sign any AMP documents that hit the size
235+
limit of 4MB. You can [monitor](monitoring.md#available-metrics) the size of
236+
your documents that have been signed, to see how close you are to the limit.
209237
210238
The packager refuses to sign any URL that results in a redirect. This is by
211239
design, as neither the original URL nor the final URL makes sense as the signed
@@ -225,6 +253,65 @@ amp-install-serviceworker will still succeed in the unsigned AMP viewer case,
225253
and crawlers may reuse the contents of the signed exchange when displaying an
226254
AMP viewer to browser versions that don't support SXG.
227255
256+
#### `<amp-script>`
257+
258+
If you have any inline `<amp-script>`s (those with a `script` attribute), then
259+
the expiration of the SXG will be set based on the minimum `max-age` of those
260+
`<amp-script>`s, minus one day (due to
261+
[backdating](https://github.com/ampproject/amppackager/issues/397)). If
262+
possible, prefer external `<amp-script>`s (those with a `src` attribute), which
263+
do not have this limitation.
264+
265+
If inline is necessary, you will need to weigh the [security
266+
risks](https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#seccons-downgrades)
267+
against the [AMP Cache requirement](docs/cache_requirements.md) for a minimum
268+
`max-age` of `345600` (4 days). For SXGs shorter than that, the Google AMP Cache
269+
will treat them as if unsigned (by showing an AMP Viewer).
270+
271+
#### How does `amppackager` process a document it cannot sign?
272+
273+
Packager will respond to every request with either a signed document, an
274+
unsigned document, or an error.
275+
276+
It will sign every document it can. It may, however, decide not to,
277+
for a number of reasons: the certificate may be invalid, the page may not be a
278+
valid AMP page, the page may not be an AMP page at all, the page may be 4MB or
279+
larger, etc.
280+
281+
If packager cannot sign the document but can fetch it, it will proxy the
282+
document unsigned.
283+
284+
If there was a problem with the gateway fetch request, or with the original
285+
request, packager will respond with an HTTP error, and log the problem to
286+
stdout.
287+
288+
You can monitor the packager's error rates, as well as the rates of signed
289+
vs unsigned documents, via the tools discussed in the next section.
290+
291+
Specifically, you can monitor the requests that resulted in a signed or an
292+
unsigned document via `documents_signed_vs_unsigned` metric, and the ones that
293+
resulted in an error - via `total_requests_by_code_and_url` metric.
294+
295+
#### Monitoring `amppackager` in production via its Prometheus endpoints
296+
297+
Once you've run the `amppackager` server in production, you may want to
298+
[monitor](monitoring.md) its health and performance. You may also monitor the
299+
performance of the underlying requests to the AMP document server. You can
300+
monitor both servers via the [Prometheus](https://prometheus.io/) endpoints
301+
provided by `amppackager`. A few examples of questions you can answer:
302+
303+
* Is `amppackager` up and running?
304+
* How many requests has it processed since it's been up?
305+
* What was the 0.9 percentile latency of handling those request?
306+
* How many of those requests have triggered a gateway request to the
307+
AMP document server?
308+
* For those gateway requests, what was the 0.9 percentile latency of
309+
the AMP document server?
310+
311+
You can perform one-off manual health inspections, visualize the real-time
312+
stats, set up alerts, and more. To learn what are all the things you can
313+
monitor, and how to do it, check the [monitoring manual](monitoring.md).
314+
228315
## Local Transformer
229316
230317
The local transformer is a library within the AMP Packager that transforms AMP

amppkg.example.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ ForwardedRequestHeaders = []
255255
# For the DNS challenge, go-acme/lego, there are certain environment variables that need to be set up which depends on
256256
# the DNS provider that you use to fulfill the DNS challenge. See:
257257
# https://go-acme.github.io/lego/dns/
258+
# To use this, build amppkg with `go build -tags dns01`; it is disabled by default because it bloats the binary.
258259
# DnsProvider = "gcloud"
259260

260261
# This config will be used if 'autorenewcert' is turned on and 'development' is turned on.

cmd/amppkg/main.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"time"
2929

3030
"github.com/pkg/errors"
31+
"github.com/prometheus/client_golang/prometheus/promhttp"
3132

3233
"github.com/ampproject/amppackager/packager/certcache"
3334
"github.com/ampproject/amppackager/packager/certloader"
@@ -42,6 +43,7 @@ import (
4243
var flagConfig = flag.String("config", "amppkg.toml", "Path to the config toml file.")
4344
var flagDevelopment = flag.Bool("development", false, "True if this is a development server.")
4445
var flagInvalidCert = flag.Bool("invalidcert", false, "True if invalid certificate intentionally used in production.")
46+
var flagStaging = flag.String("staging", "", "URL that overrides the base URL used to host certs, used for testing. Can only be used with -development flag.")
4547

4648
// IMPORTANT: do not turn on this flag for now, it's still under development.
4749
var flagAutoRenewCert = flag.Bool("autorenewcert", false, "True if amppackager is to attempt cert auto-renewal.")
@@ -104,7 +106,7 @@ func main() {
104106
} else {
105107
die(errors.Wrap(err, "initializing cert cache"))
106108
}
107-
}
109+
}
108110

109111
healthz, err := healthz.New(certCache)
110112
if err != nil {
@@ -119,15 +121,21 @@ func main() {
119121
defer rtvCache.StopCron()
120122

121123
var overrideBaseURL *url.URL
122-
if *flagDevelopment {
124+
if *flagStaging != "" {
125+
overrideBaseURL, err = url.Parse(*flagStaging)
126+
if err != nil {
127+
die(errors.Wrap(err, "parsing staging URL"))
128+
}
129+
} else if *flagDevelopment {
123130
overrideBaseURL, err = url.Parse(fmt.Sprintf("https://localhost:%d/", config.Port))
124131
if err != nil {
125132
die(errors.Wrap(err, "parsing development base URL"))
126133
}
127134
}
128135

136+
signerRequireHeaders := !*flagDevelopment
129137
signer, err := signer.New(certCache, key, config.URLSet, rtvCache, certCache.IsHealthy,
130-
overrideBaseURL, /*requireHeaders=*/!*flagDevelopment, config.ForwardedRequestHeaders)
138+
overrideBaseURL, signerRequireHeaders, config.ForwardedRequestHeaders, time.Now)
131139
if err != nil {
132140
die(errors.Wrap(err, "building signer"))
133141
}
@@ -143,7 +151,7 @@ func main() {
143151
Addr: addr,
144152
// Don't use DefaultServeMux, per
145153
// https://blog.cloudflare.com/exposing-go-on-the-internet/.
146-
Handler: logIntercept{mux.New(certCache, signer, validityMap, healthz)},
154+
Handler: logIntercept{mux.New(certCache, signer, validityMap, healthz, promhttp.Handler())},
147155
ReadTimeout: 10 * time.Second,
148156
ReadHeaderTimeout: 5 * time.Second,
149157
// If needing to stream the response, disable WriteTimeout and

cmd/gateway_server/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (s *gatewayServer) GenerateSXG(ctx context.Context, request *pb.SXGRequest)
7474
}
7575

7676
// Note: do not initialize certCache, we just want it to hold the certs for now.
77-
certCache := certcache.New(certs, nil, []string{""}, "", "", "", nil);
77+
certCache := certcache.New(certs, nil, []string{""}, "", "", "", nil, time.Now)
7878

7979
privateKey, err := util.ParsePrivateKey(request.PrivateKey)
8080
if err != nil {
@@ -116,7 +116,7 @@ func (s *gatewayServer) GenerateSXG(ctx context.Context, request *pb.SXGRequest)
116116
},
117117
}
118118

119-
packager, err := signer.New(certCache, privateKey, urlSets, s.rtvCache, shouldPackage, signUrl, false, []string{})
119+
packager, err := signer.New(certCache, privateKey, urlSets, s.rtvCache, shouldPackage, signUrl, false, []string{}, time.Now)
120120

121121
if err != nil {
122122
return errorToSXGResponse(err), nil

deploy/gcloud/Dockerfile.consumer

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Used https://medium.com/@chemidy/create-the-smallest-and-secured-golang-docker-image-based-on-scratch-4752223b7324
16+
# as a guide.
17+
18+
# Use an official Go runtime as a parent image
19+
FROM golang:1.13 as builder
20+
21+
ENV GO111MODULE=on
22+
23+
# Install git.
24+
# Git is required for fetching the dependencies.
25+
RUN apt-get update \
26+
&& apt-get install -y git
27+
28+
WORKDIR /data
29+
30+
# Run this if you clone from master branch.
31+
RUN git clone -b master https://github.com/ampproject/amppackager.git /data/amppackager
32+
# RUN git clone https://github.com/ampproject/amppackager.git /data/amppackager
33+
34+
WORKDIR /data/amppackager/cmd/amppkg
35+
36+
# Build the binary.
37+
# See: https://medium.com/on-docker/use-multi-stage-builds-to-inject-ca-certs-ad1e8f01de1b
38+
# https://github.com/kelseyhightower/contributors
39+
# Avoid "x509: failed to load system roots and no roots provided" by bundling root certificates.
40+
# Avoid dynamic linking by using the pure Go net package (-tags netgo)
41+
# Avoid dynamic linking by disabling cgo (CGO_ENABLED=0)
42+
# Reduce binary size by omitting dwarf information (-ldflags '-w')
43+
RUN CGO_ENABLED=0 GOOS=linux go build -a -tags netgo -ldflags '-w' -o /go/bin/amppkg
44+
45+
FROM alpine:latest as certs
46+
47+
RUN apk --update add ca-certificates
48+
49+
# Build a small executable from docker alpine. Docker alpine is needed because
50+
# bash is required to be present by the deployer as it prints the env variables
51+
# listed below for verifiying the docker image.
52+
FROM alpine:latest
53+
54+
# Copy the certs from certs image.
55+
ENV PATH=/bin
56+
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
57+
58+
# Copy the AMP packager binary into our app dir inside the container.
59+
COPY --from=builder /go/bin/amppkg .
60+
61+
# Make port 8080 available to the world outside this container. This
62+
# port must match the AMP Packager port configured in the toml file.
63+
EXPOSE 8080
64+
65+
ENV PATH=$PATH:.
66+
67+
# This env var is used by click-to-deploy deployer, right now needs to be
68+
# manually synced with C2D_RELEASE in the other Docker images for AMP Packager
69+
# Deployer currently in https://github.com/banaag/click-to-deploy but will move
70+
# to https://github.com/GoogleCloudPlatform/click-to-deploy.
71+
ENV C2D_RELEASE=0.0.1
72+
73+
# Start the AMP Packager
74+
ENTRYPOINT ["amppkg"]
75+
76+
# Set default flags to run in development mode.
77+
CMD ["-config=/consumer/amppkg_consumer.toml"]
78+

0 commit comments

Comments
 (0)