Proxy
The proxy service is an API-Gateway for the ownCloud Infinite Scale microservices. Every HTTP request goes through this service. Authentication, logging and other preprocessing of requests also happens here. Mechanisms like request rate limiting or intrusion prevention are not included in the proxy service and must be setup in front like with an external reverse proxy.
The proxy service is the only service communicating to the outside and needs therefore usual protections against DDOS, Slow Loris or other attack vectors. All other services are not exposed to the outside, but also need protective measures when it comes to distributed setups like when using container orchestration over various physical servers.
Authentication
The following request authentication schemes are implemented:
- Basic Auth (Only use in development, never in production setups!)
- OpenID Connect
- Signed URL
- Public Share Token
Configuring Routes
The proxy handles routing to all endpoints that ocis offers. The currently availabe default routes can be found in the code. Changing or adding routes can be necessary when writing own ocis extensions.
Due to the complexity when defining routes, these can only be defined in the yaml file but not via environment variables.
For overwriting default routes, use the following yaml example:
policies:
- name: ocis
routes:
- endpoint: /
service: com.owncloud.web.web
- endpoint: /dav/
service: com.owncloud.web.ocdav
For adding additional routes to the default routes use:
additional_policies:
- name: ocis
routes:
- endpoint: /custom/endpoint
service: com.owncloud.custom.custom
A route has the following configurable parameters:
endpoint: "" # the url that should be routed
service: "" # the service the url should be routed to
unprotected: false # with false (default), calling the endpoint requires authorization.
# with true, anyone can call the endpoint without authorisation.
Automatic User and Group Provisioning
When using an external OpenID Connect IDP, the proxy can be configured to automatically provision users upon their first login.
Prequisites
A number of prerequisites must be met for automatic user provisioning to work:
- ownCloud Infinite Scale must be configured to use an external OpenID Connect IDP
- The
graphservice must be configured to allow updating users and groups (GRAPH_LDAP_SERVER_WRITE_ENABLED). - The IDP must return a unique value in the user's claims (as part of the
userinfo response and/or the access tokens) that can be used to identify
the user. This claim needs to be stable and cannot be changed for the whole
lifetime of the user. That means, if a claim like
emailorpreferred_usernameis used, you must ensure that the user's email address or username never changes.
Configuration
To enable automatic user provisioning, the following environment variables must be set for the proxy service:
PROXY_AUTOPROVISION_ACCOUNTS
Set totrueto enable automatic user provisioning.PROXY_AUTOPROVISION_CLAIM_USERNAME
The name of an OIDC claim whose value should be used as the username for the autoprovsioned user in ownCloud Infinite Scale. Defaults topreferred_username. Can also be set to e.g.subto guarantee a unique and stable username.PROXY_AUTOPROVISION_CLAIM_EMAIL
The name of an OIDC claim whose value should be used for themailattribute of the autoprovisioned user in ownCloud Infinite Scale. Defaults toemail.PROXY_AUTOPROVISION_CLAIM_DISPLAYNAME
The name of an OIDC claim whose value should be used for thedisplaynameattribute of the autoprovisioned user in ownCloud Infinite Scale. Defaults toname.PROXY_AUTOPROVISION_CLAIM_GROUPS
The name of an OIDC claim whose value should be used to maintain a user's group membership. The claim value should contain a list of group names the user should be a member of. Defaults togroups.PROXY_USER_OIDC_CLAIM
When resolving and authenticated OIDC user, the value of this claims is used to lookup the user in the users service. For auto provisioning setups this usually is the same claims as set viaPROXY_AUTOPROVISION_CLAIM_USERNAME.PROXY_USER_CS3_CLAIM
This is the name of the user attribute in ocis that is used to lookup the user by the value of thePROXY_USER_OIDC_CLAIM. For auto provisioning setups this usually needs to be set tousername.
How it Works
When a user logs into ownCloud Infinite Scale for the first time, the proxy
checks if that user already exists. This is done by querying the users service for users,
where the attribute set in PROXY_USER_CS3_CLAIM matches the value of the OIDC
claim configured in PROXY_USER_OIDC_CLAIM.
If the users does not exist, the proxy will create a new user via the graph
service using the claim values configured in
PROXY_AUTOPROVISION_CLAIM_USERNAME, PROXY_AUTOPROVISION_CLAIM_EMAIL and
PROXY_AUTOPROVISION_CLAIM_DISPLAYNAME.
If the user does already exist, the proxy will check if the user's email or
displayname has changed and updates those accordingly via graph service.
Next, the proxy will check if the user is a member of the groups configured in
PROXY_AUTOPROVISION_CLAIM_GROUPS. It will add the user to the groups listed
via the OIDC claim that holds the groups defined in the envvar and removes it from
all other groups that he is currently a member of.
Groups that do not exist in the external IDP yet will be created. Note: This can be a
somewhat costly operation, especially if the user is a member of a large number of
groups. If the group memberships of a user are changed in the IDP after the
first login, it can take up to 5 minutes until the changes are reflected in Infinite Scale.
Automatic Quota Assignments
It is possible to automatically assign a specific quota to new users depending on their role.
To do this, you need to configure a mapping between roles defined by their ID and the quota in bytes.
The assignment can only be done via a yaml configuration and not via environment variables.
See the following proxy.yaml config snippet for a configuration example.
role_quotas:
<role ID1>: <quota1>
<role ID2>: <quota2>
Automatic Role Assignments
When users login, they do automatically get a role assigned. The automatic role assignment can be
configured in different ways. The PROXY_ROLE_ASSIGNMENT_DRIVER environment variable (or the driver
setting in the role_assignment section of the configuration file select which mechanism to use for
the automatic role assignment.
When set to default, all users which do not have a role assigned at the time for the first login will
get the role 'user' assigned. (This is also the default behavior if PROXY_ROLE_ASSIGNMENT_DRIVER
is unset.
When PROXY_ROLE_ASSIGNMENT_DRIVER is set to oidc the role assignment for a user will happen
based on the values of an OpenID Connect Claim of that user. The name of the OpenID Connect Claim to
be used for the role assignment can be configured via the PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM
environment variable. It is also possible to define a mapping of claim values to role names defined
in Infinite Scale via a yaml configuration. See the following proxy.yaml snippet for an example.
role_assignment:
driver: oidc
oidc_role_mapper:
role_claim: ocisRoles
role_mapping:
- role_name: admin
claim_value: myAdminRole
- role_name: spaceadmin
claim_value: mySpaceAdminRole
- role_name: user
claim_value: myUserRole
- role_name: guest
claim_value: myGuestRole
This would assign the role admin to users with the value myAdminRole in the claim ocisRoles.
The role user to users with the values myUserRole in the claims ocisRoles and so on.
Claim values that are not mapped to a specific ownCloud Infinite Scale role will be ignored.
Note: An ownCloud Infinite Scale user can only have a single role assigned. If the configured
role_mapping and a user's claim values result in multiple possible roles for a user, the order in
which the role mappings are defined in the configuration is important. The first role in the
role_mappings where the claim_value matches a value from the user's roles claim will be assigned
to the user. So if e.g. a user's ocisRoles claim has the values myUserRole and
mySpaceAdminRole that user will get the ocis role spaceadmin assigned (because spaceadmin
appears before user in the above sample configuration).
If a user's claim values don't match any of the configured role mappings an error will be logged and the user will not be able to login.
The default role_claim (or PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM) is roles. The default role_mapping is:
- role_name: admin
claim_value: ocisAdmin
- role_name: spaceadmin
claim_value: ocisSpaceAdmin
- role_name: user
claim_value: ocisUser
- role_name: guest
claim_value: ocisGuest
Recommendations for Production Deployments
In a production deployment, you want to have basic authentication (PROXY_ENABLE_BASIC_AUTH) disabled which is the default state. You also want to setup a firewall to only allow requests to the proxy service or the reverse proxy if you have one. Requests to the other services should be blocked by the firewall.
Caching
The proxy service can use a configured store via PROXY_OIDC_USERINFO_CACHE_STORE. Possible stores are:
memory: Basic in-memory store and the default.redis-sentinel: Stores data in a configured Redis Sentinel cluster.nats-js-kv: Stores data using key-value-store feature of nats jetstreamnoop: Stores nothing. Useful for testing. Not recommended in production environments.ocmem: Advanced in-memory store allowing max size. (deprecated)redis: Stores data in a configured Redis cluster. (deprecated)etcd: Stores data in a configured etcd cluster. (deprecated)nats-js: Stores data using object-store feature of nats jetstream (deprecated)
Other store types may work but are not supported currently.
Note: The service can only be scaled if not using memory store and the stores are configured identically over all instances!
Note that if you have used one of the deprecated stores, you should reconfigure to one of the supported ones as the deprecated stores will be removed in a later version.
Store specific notes:
- When using
redis-sentinel, the Redis master to use is configured via e.g.OCIS_CACHE_STORE_NODESin the form of<sentinel-host>:<sentinel-port>/<redis-master>like10.10.0.200:26379/mymaster. - When using
nats-js-kvit is recommended to setOCIS_CACHE_STORE_NODESto the same value asOCIS_EVENTS_ENDPOINT. That way the cache uses the same nats instance as the event bus. - When using the
nats-js-kvstore, it is possible to setOCIS_CACHE_DISABLE_PERSISTENCEto instruct nats to not persist cache data on disc.
Presigned Urls
To authenticate presigned URLs the proxy service needs to read signing keys from a store that is populated by the ocs service. Possible stores are:
nats-js-kv: Stores data using key-value-store feature of nats jetstreamredis-sentinel: Stores data in a configured Redis Sentinel cluster.ocisstoreservice: Stores data in the legacy ocis store service. Requires settingPROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_NODEStocom.owncloud.api.store.
The memory or ocmem stores cannot be used as they do not share the memory from the ocs service signing key memory store, even in a single process.
Make sure to configure the same store in the ocs service.
Store specific notes:
- When using
redis-sentinel, the Redis master to use is configured via e.g.OCIS_CACHE_STORE_NODESin the form of<sentinel-host>:<sentinel-port>/<redis-master>like10.10.0.200:26379/mymaster. - When using
nats-js-kvit is recommended to setOCS_PRESIGNEDURL_SIGNING_KEYS_STORE_NODESto the same value asPROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_NODES. That way the ocs uses the same nats instance as the proxy service. - When using the
nats-js-kvstore, it is possible to setPROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_DISABLE_PERSISTENCEto instruct nats to not persist signing key data on disc. - When using
ocisstoreservicethePROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_NODESmust be set to the service namecom.owncloud.api.store. It does not support TTL and stores the presigning keys indefinitely. Also, the store service needs to be started.
Special Settings
When using the ocis IDP service instead of an external IDP:
- Use the environment variable
OCIS_URLto define how ocis can be accessed, mandatory usehttpsas protocol for the URL. - If no reverse proxy is set up, the
PROXY_TLSenvironment variable must be set totruebecause the embeddedlibreConnectshipped with the IDP service has a hard check if the connection is on TLS and uses the HTTPS protocol. If this mismatches, an error will be logged and no connection from the client can be established. PROXY_TLScan be set tofalseif a reverse proxy is used and the https connection is terminated at the reverse proxy. When setting tofalse, the communication between the reverse proxy and ocis is not secured. If set totrue, you must provide certificates.
Metrics
The proxy service in ocis has the ability to expose metrics in the prometheus format. The metrics are exposed on the /metrics endpoint. There are two ways to run the ocis proxy service which has an impact on the number of metrics exposed.
1) Single Process Mode
In the single process mode, all ocis services are running inside a single process. This is the default mode when using the ocis server command to start the services. In this mode, the proxy service exposes metrics about the proxy service itself and about the ocis services it is proxying. This is due to the nature of the prometheus registry which is a singleton. The metrics exposed by the proxy service itself are prefixed with ocis_proxy_ and the metrics exposed by other ocis services are prefixed with ocis_<service-name>_.
2) Standalone Mode
In this mode, the proxy service only exposes its own metrics. The metrics of the other ocis services are exposed on their own metrics endpoints.
Available Metrics
The following metrics are exposed by the proxy service:
| Metric Name | Description | Labels |
|---|---|---|
ocis_proxy_requests_total |
Counter metric which reports the total number of HTTP requests. | method: HTTP method of the request |
ocis_proxy_errors_total |
Counter metric which reports the total number of HTTP requests which have failed. That counts all response codes >= 500 | method: HTTP method of the request |
ocis_proxy_duration_seconds |
Histogram of the time (in seconds) each request took. A histogram metric uses buckets to count the number of events that fall into each bucket. | method: HTTP method of the request |
ocis_proxy_build_info{version} |
A metric with a constant 1 value labeled by version, exposing the version of the ocis proxy service. |
version: Build version of the proxy |
Prometheus Configuration
The following is an example prometheus configuration for the single process mode. It assumes that the proxy debug address is configured to bind on all interfaces PROXY_DEBUG_ADDR=0.0.0.0:9205 and that the proxy is available via the ocis service name (typically in docker-compose). The prometheus service detects the /metrics endpoint automatically and scrapes it every 15 seconds.
global:
scrape_interval: 15s
scrape_configs:
- job_name: ocis_proxy
static_configs:
- targets: ["ocis:9205"]