Back to home page

EIC code displayed by LXR

 
 

    


Warning, /swf-remote/docs/live-data-access.md is written in an unsupported language. File is not indexed.

0001 # Live-data access policy
0002 
0003 ## Purpose
0004 
0005 `epic-devcloud.org` publishes ePIC monitoring information from outside BNL,
0006 while the authoritative monitoring application and its data sources run on
0007 protected infrastructure inside it. Every `/prod/` page is rendered by
0008 swf-monitor and retrieved over the SSH tunnel, so serving a page costs an
0009 upstream page build on `pandaserver02`.
0010 
0011 Automated clients conceal their identity, ignore crawler exclusions, and
0012 traverse expensive pages concurrently. One such client enumerated the PCS
0013 physics facet space — tens of thousands of distinct filter combinations, no
0014 two alike — at more than one request per second, exhausting the swf-remote
0015 WSGI pool and, through the shared Apache instance, the unrelated service at
0016 `/doc/`. Address-based blocking did not reach it: the client moved to a
0017 residential proxy network presenting one request per exit address.
0018 
0019 Access therefore depends on identity rather than on traffic signatures. A
0020 request that cannot present an account does not reach the tunnel.
0021 
0022 ## Access policy
0023 
0024 Signing in is required for every proxied surface: HTML pages, DataTables
0025 requests, JSON endpoints, filter counts, and the REST proxies. Protecting only
0026 the initial HTML response would be insufficient, because a page issues further
0027 requests after it loads.
0028 
0029 Three paths remain open without an account:
0030 
0031 - the login page and the GitHub authorization callback, under `/accounts/`;
0032 - static assets, which are proxied and whose absence leaves the login page
0033   unstyled;
0034 - the landing page at `/prod/`, which is rendered locally rather than proxied.
0035 
0036 The landing page identifies the service and offers sign-in. Because it is
0037 local, an anonymous visitor — including a crawler — costs nothing upstream,
0038 and liveness pollers that watch `/prod/` continue to receive a 200 response.
0039 
0040 Machine clients that require current information use an authenticated service
0041 identity. Authorization does not depend on a User-Agent allowlist. Signed-in
0042 users are not rate-limited unless observed use shows a need.
0043 
0044 ## Establishing an account
0045 
0046 An account is established either by a local username and password or by
0047 signing in with GitHub, which creates the Django account on first use so that
0048 collaborators need no provisioned credential. Both carry the same authority.
0049 
0050 Membership of the `eic` GitHub organization is not a condition of signing in.
0051 Authentication alone supplies the protection the policy needs, because a
0052 crawler does not complete an OAuth flow, whereas an organization test would
0053 exclude collaborators who do not use GitHub.
0054 
0055 A GitHub identity whose verified address matches an existing account signs
0056 into that account and links the two, instead of creating a second one. The
0057 match is against verified `EmailAddress` records, with a fallback to the user
0058 record's own address. Two accounts carrying one address are disambiguated by
0059 the verified record. This requires `SOCIALACCOUNT_QUERY_EMAIL`: it otherwise
0060 follows `SOCIALACCOUNT_EMAIL_REQUIRED`, and while off the provider's
0061 `/user/emails` call is skipped, so no address arrives marked verified and no
0062 account can be matched.
0063 
0064 ## Sessions
0065 
0066 A session lasts 14 days and the window rolls: each request extends expiry, so
0067 continued use keeps a person signed in and only inactivity ends the session.
0068 Django writes the session record only when the session is non-empty, so
0069 anonymous traffic adds no database write. Expired records are not reaped
0070 automatically; `manage.py clearsessions` removes them.
0071 
0072 ## Component responsibilities
0073 
0074 ### swf-remote
0075 
0076 - Enforces the policy, in `swf_remote_project/login_wall.py`. Enforcement
0077   belongs here because a request refused at this boundary never crosses the
0078   tunnel, whereas the same rule applied upstream would admit the traffic
0079   before rejecting it.
0080 - Runs the check as middleware. `remote_app/urls.py` ends in catch-all proxy
0081   routes so that new swf-monitor pages need no route definition here; a
0082   per-view decorator would leave each of them unprotected.
0083 - Authenticates Django users, by local credential or GitHub sign-in, and
0084   forwards only locally established user identity to swf-monitor.
0085 - Adds trusted tunnel metadata for traffic correlation: `X-Remote-Access`,
0086   `X-Remote-Request-ID`, `X-Remote-Client`, and `X-Remote-User-Agent`. The
0087   anonymous client identifier is a signed observability cookie and grants no
0088   access.
0089 
0090 ### swf-monitor
0091 
0092 - Owns the expensive page and data construction paths.
0093 - Establishes user identity from `X-Remote-User`, through
0094   `TunnelAuthMiddleware`, and treats a request without that header as
0095   anonymous. Tunnel metadata is trusted only on localhost requests arriving
0096   through the SSH tunnel. `X-Remote-Access` carries the classification;
0097   `X-Remote-User` alone establishes identity.
0098 - Needs no change for this policy. Its own users, reaching it directly inside
0099   the firewall, are unaffected.
0100 
0101 ## Observability
0102 
0103 A Snapper `traffic` scope records anonymous and authenticated request rates,
0104 policy denials, upstream concurrency, response size, route-family fan-out, and
0105 crawler exclusions. Time cuts provide source, account or anonymous identity,
0106 User-Agent, route family, and requested-path drilldown.
0107 
0108 A CAPCOM `swf-traffic` state reports whether the policy is operating normally,
0109 linking to the Snapper traffic report. The policy is healthy when no anonymous
0110 request reaches a proxied surface and upstream concurrency stays below the
0111 capacity signed-in users require.
0112 
0113 ## Public cached access
0114 
0115 Anonymous access to cached monitoring information, rather than to nothing, is
0116 a possible later relaxation. It would return an existing cached result to an
0117 anonymous request while reserving live computation and cache refreshes to
0118 signed-in users, and would restore public visibility of monitoring
0119 information without restoring the load that made sign-in necessary.
0120 
0121 It depends on conditions that do not hold today. The cache would have to cover
0122 the expensive surfaces rather than selected products, cache keys would have to
0123 be bounded and canonical so that arbitrary query parameters cannot create
0124 entries or turn a miss into live work, expiry would have to retain the last
0125 usable public result for stale service, and no authenticated or personalized
0126 content could enter a public cached representation. Enforcement would move to
0127 swf-monitor, which owns the caches, at the cost of admitting the traffic to
0128 the tunnel before answering it.
0129 
0130 ## Contingency for anonymous load
0131 
0132 The landing page is local and inexpensive, so anonymous traffic no longer
0133 reaches the tunnel regardless of volume. If anonymous request volume later
0134 burdens swf-remote or the ingress itself,
0135 [Anubis](https://github.com/TecharoHQ/anubis) is the preferred contingency at
0136 the public ingress. It applies an automatic JavaScript proof-of-work challenge
0137 and a signed pass cookie, requiring little user interaction but adding an
0138 ingress service, policy, signing key, state, and monitoring burden. It would
0139 apply to anonymous traffic only; signed-in users and service identities bypass
0140 it, and static assets, health endpoints, crawler policy files, and the login
0141 path remain reachable without the challenge.