# Service Overview

> Octelium documentation. Canonical page: <https://octelium.com/docs/octelium/latest/management/core/service/overview>.

Each protected resource is represented in the *Cluster* by a *Service*. A *Service* is implemented by an identity-aware proxy (IaP) called [*Vigil*](https://octelium.com/docs/octelium/latest/reference/components.md#vigil), which abstracts all dynamic network-layer details of the protected resource behind it and is capable of providing access control, dynamic configuration such as routing as well as visibility and access logging at the application-layer for various protocols including HTTP, SSH, PostgreSQL, MySQL, among others (read more about *Service* modes [here](#mode)).

> **Note:**
>
> This guide is concerned about the configuration of *Services*. If you want to know about *Service* policies, please learn more about access control [here](https://octelium.com/docs/octelium/latest/management/core/policy.md).

## Namespaces

Each *Service* belongs to a single *Namespace*. *Namespaces* are a way to group a collection of *Services* according to your needs and you are free to create as many *Namespaces* as you want. By default, if you do not explicitly specify a *Namespace*, the *Service* will automatically belong to the `default` *Namespace* which is created automatically upon the *Cluster*'s installation. You can read more about how to manage *Namespaces* and how they affect DNS and *Service* addressing [here](https://octelium.com/docs/octelium/latest/management/core/namespace.md).

> **Note:**
>
> *Service* names starting with `octelium` are reserved and cannot be used.

## Listing Services

You can list the *Cluster*'s *Services* (read more about listing resources [here](https://octelium.com/docs/octelium/latest/management/core/overview.md#listing-resources)) as follows:

```bash
octeliumctl get service
# Or simply
octeliumctl get svc

# Or list by a certain Namespace
octeliumctl get svc --namespace default
# Or simply
octeliumctl get svc -n production

# Show a certain Service
octeliumctl get svc nginx.production
```

You can also delete a *Service* by its name via `octeliumctl delete service` command as follows:

```bash
octeliumctl delete service demo-nginx
# Or simply
octeliumctl del svc demo-nginx
```

## Upstream

*Users* can only access the protected resources of the *Cluster* through its *Services*. Therefore, a *Service* must have an upstream whose address belongs to the actual protected resource. An upstream can be either directly accessible to the *Service* from within the *Cluster* or indirectly via an actively connected *User* assigned to serve the *Service*. Moreover, a *Service* can deploy, manage and scale containers on top of the underlying Kubernetes infrastructure and serve them as an upstream (read more[here](https://octelium.com/docs/octelium/latest/management/core/service/managed-containers.md)).

### Directly Accessible by the Cluster

The upstream can be a private or public IP address or FQDN that is reachable directly from within the *Cluster*. Some examples are:

- A Kubernetes pod IP address or Kubernetes service's FQDN in the same Kubernetes cluster hosting the Octelium *Cluster* (e.g. `http://10.244.0.13`, `postgres://pg.default.svc`, etc...)
- A private cloud resource reachable from within the *Cluster* (e.g. `postgresql://db1.123456789012.us-east-1.rds.amazonaws.com:5432`, `tcp://my-custom-app:9090`)
- A public FQDN of a public resource (e.g. `https://api.sandbox.paypal.com`, `https://news.ycombinator.com`)

Here is an example:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: POSTGRES
  config:
    upstream:
      url: postgres://pg.my-private-network.local
```

### Remotely via a Connected User

The upstream can also be a private/public IP address or FQDN that is remotely reachable via a connected *User* (i.e. via the `octelium connect` command). This opens the door to serving *Services* from anywhere from outside the *Cluster* (e.g. your laptop behind a NAT, Docker containers, Kubernetes pods from remote Kubernetes clusters, IoT, etc...). Here is an example:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: POSTGRES
  config:
    upstream:
      url: postgres://pg.my-private-network.local
      # !mark
      user: john
```

> **Note:**
>
> Note that the upstream `postgres://pg.my-private-network.local` here is is the address that is reachable from the side of the host of the *User* `john`. This address is not directly reachable from within the *Cluster* itself. You can see detailed examples [here](https://octelium.com/docs/octelium/latest/management/guide/service/http/open-source-self-hosted-ngrok-alternative.md) and [here](https://octelium.com/docs/octelium/latest/management/guide/service/homelab/website-api-hosting-nat.md).

When remotely serving *Services* from the *User*'s side, that *User*'s client has to explicitly inform the *Cluster* (i.e. via the `--serve` and `--serve-all` flags of the  `octelium connect` command) that they are willing to serve one, multiple, or all *Services* assigned to them. Read more about serving *Services* [here](https://octelium.com/docs/octelium/latest/user/cli/connect.md#serving-services).

### Load Balancing

You are not restricted to having only a single upstream for your *Service*. Octelium supports having more than one upstream addresses, and currently random load balancing is automatically enforced among the different upstreams. Here is an example:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  config:
    upstream:
      loadbalance:
        endpoints:
        - url: https://backend1.example.com
        - url: https://backend2.example.com
        - url: https://backend3.example.com
```

If an upstream hosted by a *User* is served by multiple active *Sessions* (i.e. multiple instances of `octelium connect --serve-all` or `octelium connect --serve <SERVICE_NAME>`), then round robin load balancing is automatically enforced among the different hosting *Sessions* of that upstream.

### Managed Containers

In addition to serving upstreams via their private/public addresses as illustrated above, the *Cluster* is also capable of reusing the underlying Kubernetes cluster to automatically deploy your containerized applications and seamlessly serve them as the upstream for the *Service*. You can read more about the managed containers mode [here](https://octelium.com/docs/octelium/latest/management/core/service/managed-containers.md).

### Embedded SSH

In addition to serving SSH via the application-layer aware SSH mode (see *Service* modes below [here](#mode)), *Services* can also provide secretless SSH access served by connected `octelium` clients which can run an embedded SSH server from within. You can read more about the embedded SSH mode [here](https://octelium.com/docs/octelium/latest/management/core/service/embedded-ssh.md).

## DNS

Each *Service* has a private FQDN in the format `<SERVICE>.<NAMESPACE>.local.<DOMAIN>`. If a *Service* is exposed publicly (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/clientless.md)), it additionally assumes the public FQDN `<SERVICE>.<NAMESPACE>.<DOMAIN>`. For example, if the *Cluster* domain is `example.com`, the *Service* `webapp.production` has the private FQDN `webapp.production.local.example.com` and, when public, the public FQDN `webapp.production.example.com`.

The name `default` shortens FQDNs. A *Service* in the `default` *Namespace* additionally gets `<SERVICE>.local.<DOMAIN>` (and publicly `<SERVICE>.<DOMAIN>`). Likewise, a *Service* named `default` in any *Namespace* additionally gets `<NAMESPACE>.local.<DOMAIN>` (and publicly `<NAMESPACE>.<DOMAIN>`).

For example, the *Service* `webapp.default` which exists in the `default` *Namespace*, additionally has the private FQDN `<SERVICE>.local.<DOMAIN>` `webapp.local.example.com`

The `default` *Namespace* is a special *Namespace* that is created automatically by the *Cluster* upon its installation and has a unique feature when it comes to DNS. It provides for its *Services* the additional private FQDN `<SERVICE>.local.<DOMAIN>` and the public FQDN `<SERVICE>.<DOMAIN>` leading to shorter and easier-to-type FQDNs. For example, if the *Cluster* domain is `example.com`, the above *Service* will have the private FQDN `webapp.local.example.com` and the public FQDN `webapp.example.com` when the BeyondCorp mode is enabled.

To sum it up, here is a table showing the FQDN and hostname values for different *Service* and *Namespace* names:

| *Service*         | Private FQDNs                                            | Public FQDNs                                 |
| ----------------- | -------------------------------------------------------- | -------------------------------------------- |
| webapp.production | webapp.production.local.example.com                      | webapp.production.example.com                |
| webapp.default    | webapp.local.example.comwebapp.default.local.example.com | webapp.example.comwebapp.default.example.com |
| default.webapp    | webapp.local.example.comdefault.webapp.local.example.com | webapp.example.comdefault.webapp.example.com |

## Port

The port at which the identity-aware proxy implementing the *Service* is listening can be automatically inferred from the upstream URL or explicitly set. Here are some examples of port numbers inferred from the upstream URL:

| Backend URL                                                                                    | Port |
| ---------------------------------------------------------------------------------------------- | ---- |
| `http://example.com`                                                                           | 80   |
| `https://example.com` with TLS disabled (read about *Service* TLS [here](#listening-over-tls)) | 80   |
| `https://example.com` with TLS enabled                                                         | 443  |
| `https://example.com:3000`                                                                     | 3000 |
| `postgres://pg.my-private-network.local`                                                       | 5432 |
| `ssh://usr-1.users`                                                                            | 22   |

Since there are many L7 protocols with different default ports, Octelium cannot recognize every possibility on its own and you might have to provide the port in the URL in the form of `PROTOCOL://HOSTNAME:PORT` (e.g. `myprotocol://svc.local:9090`) in order to extract the port value.

You can also explicitly set the *Service*'s port value to be different from that used by the upstream. Here is an example:

```yaml
kind: Service
metadata:
  name: ssh1
spec:
  mode: SSH
  config:
    upstream:
      url: ssh://my-ssh.private.local
  # !mark
  port: 2022
```

Now *Users* can access `ssh1` when connected as follows:

```bash
ssh <USER>@ssh1 -p 2022
```

## Mode

A *Service* is implemented by [*Vigil*](https://octelium.com/docs/octelium/latest/reference/components.md#vigil). *Vigil* is an identity-aware proxy (IAP) capable of understanding various widely used layer-7 protocols. The application-layer awareness provided by *Vigil* not only enables you to control access based on L7 information (e.g. HTTP headers and paths, Kubernetes verbs and resources, SSH users, etc...), provide secretless access that eliminates L7 credentials (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/secretless.md)), L7 aware dynamic configuration such as routing to different upstreams and their credentials (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/dynamic-config.md)),  but it also provides you with L7 aware auditing and access logging (read more [here](https://octelium.com/docs/octelium/latest/management/core/visibility.md)). Currently, a *Service* supports the following modes:

- `TCP` (Read more [here](https://octelium.com/docs/octelium/latest/management/core/service/tcp.md)) This should be the fallback mode for a generic TCP-based application-layer protocol that is not supported by default by *Vigil* or when you do not want to benefit from the L7 aware mode provided by the *Service* and simply treat it as raw generic TCP traffic.
- `UDP` (Read more [here](https://octelium.com/docs/octelium/latest/management/core/service/udp.md))
- `HTTP` (Read more about HTTP mode which can be used for any HTTP-based resources (e.g. APIs) [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md)).
- `SSH`(Read more [here](https://octelium.com/docs/octelium/latest/management/core/service/ssh.md)).
- `POSTGRES` (Read more about the The PostgreSQL mode [here](https://octelium.com/docs/octelium/latest/management/core/service/postgres.md)).
- `MYSQL` (Read more about the MySQL mode [here](https://octelium.com/docs/octelium/latest/management/core/service/mysql.md)).
- `KUBERNETES` (Read more about the Kubernetes mode [here](https://octelium.com/docs/octelium/latest/management/core/service/kubernetes.md)).
- `GRPC` (Read more about the gRPC mode [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#grpc-mode).
- `DNS` (Read more about the DNS mode [here](https://octelium.com/docs/octelium/latest/management/core/service/dns.md)).
- `WEB` (Read more about the Web mode which can be used for Web-based applications [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#web-app-mode)).
- `SOCKS5` (Read more about the SOCKS5 proxy mode [here](https://octelium.com/docs/octelium/latest/management/core/service/socks5.md)).
- `RDP_WEB` (Read more about the browser-based RDP mode [here](https://octelium.com/docs/octelium/latest/management/core/service/rdp.md)).

## Listening over TLS

A *Service*, by default, listens over plaintext TCP. If you want a *Service* whose mode supports TLS (e.g. `TCP`, `HTTP`, `POSTGRES`) to be accessed over TLS, then you have to enable TLS as follows:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  config:
    upstream:
      url: https://nginx.local
  # !mark
  isTLS: true
```

Now, *Users* can access the *Service* `svc1` at the private URL `https://svc1.local.<DOMAIN>`.

## Upstreams over TLS

The *Service* can automatically connect to an upstream that is running over TLS if the upstream URL has the scheme `https` or `tls`. You can configure the TLS client-side configuration, used by the *Service* to connect to the upstream. For example, you might want to add/override the trusted CAs, or you might want to client TLS private key in order to use mTLS. Here is an example:

```yaml
kind: Service
metadata:
  name: nats
spec:
  mode: TCP
  config:
    upstream:
      url: tls://my-nats.default.svc:9090
    tls:
      trustedCAs:
      - |
        -----BEGIN CERTIFICATE-----
        CA_1
        -----END CERTIFICATE-----
      - |
        -----BEGIN CERTIFICATE-----
        CA_2
        -----END CERTIFICATE-----
      # By default, adding trusted CAs overrides the default system trusted CAs.
      appendToSystemPool: true
      # Totally skips verifying the server certificate provided by the upstream
      insecureSkipVerify: false
      # mTLS client PEM private key
      clientCertificate:
        fromSecret: nats-tls-private-key
```

> **Note:**
>
> You can read in detail about secretless access with mutual TLS (mTLS) [here](https://octelium.com/docs/octelium/latest/management/core/service/secretless.md#mutual-tls).

## Disabling a Service

Once you disable a *Service*, it stops serving new requests. You can use disable a *Service* in order to temporarily suspend a *Service* without having to completely delete it and re-create it later. Here is an example:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  # !mark
  isDisabled: true
  config:
    upstream:
      url: https://example.com
```

## Deployment

Octelium *Services* are implemented as Kubernetes [deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) with a single replica by default. Octelium enables you to effortlessly scale up or down your *Services* either by changing the number of replicas (which translates to deployment replicas) as shown below.

### Setting Replicas

You can set replicas for a *Service* as follows:

```yaml
kind: Service
metadata:
  name: svc1
spec:
  mode: HTTP
  config:
    upstream:
      url: https://example.com
  # !mark(1:2)
  deployment:
    replicas: 5
```

## Policies

*Policies* (read more about *Policies* and access control [here](https://octelium.com/docs/octelium/latest/management/core/policy.md)) can be created and/or attached to *Services*, where they can act as resource-based policies for a certain *Service*. When a request comes to that *Service*, all the rules of the *InlinePolicies* and attached *Policies* of that *Service* are evaluated.

```yaml
kind: Service
metadata:
  name: example
spec:
  mode: HTTP
  config:
    upstream:
      url: https://example.com
  authorization:
    policies: ["policy-1", "policy-2"]
    inlinePolicies:
      - spec:
          rules:
            - effect: DENY
              condition:
                match: '"group-1" in ctx.user.spec.groups'
```

## Attributes

You can extend the information of a *Service* by providing it additional information manually or dynamically via the APIs (read more [here](https://octelium.com/docs/octelium/latest/management/guide/sdk.md)) from external sources (e.g. IAM platforms, SIEM tools, threat intelligence tools, incident alerting and on-call management tools, etc...). Such additional information can be especially useful for extending access control and making it as fine-grained and dynamic as you wish (read more [here](https://octelium.com/docs/octelium/latest/management/core/policy.md#extending-access-control)). Here is an example:

```yaml
kind: Service
metadata:
  name: db.production
spec:
  mode: POSTGRES
  # The rest of your configs
  attrs:
    isProduction: true
    priority: 1000
    someKey:
      key1: val1
      key2: 100
      key3: true
      key4:
        subKey1: subVal1
```

> **Note:**
>
> The `attrs` field is also available for *Groups*, *Users* and *Namespaces*.

## API Reference

[Service JSON Schema (Octelium core/v1, latest documentation)](https://octelium.com/schemas/octelium/latest/core.v1.Service.schema.json)
