> For the complete documentation index, see [llms.txt](https://docs.kiloiot.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kiloiot.io/kilo-mioty-service-center/security/security-basics.md).

# Security Basics

KiloCenter security basics: default credentials to replace, TLS certificates, and network exposure limits.

KiloCenter security configuration controls access to service interfaces and protects communication with base stations, applications, and operators. The person running the installation is responsible for credentials, certificates, authentication settings, and network exposure.

Use this guide before making a development installation available to other users or networks. Review the active [configuration](/kilo-mioty-service-center/getting-started/configuration-basics.md), replace convenience credentials, and expose only the interfaces required by your deployment. A running local stack is the starting point, not evidence that production access has been configured.

### What does this guide achieve?

Establish a secure baseline for KiloCenter deployments.

### Default Credentials

Local development includes convenience credentials that must be changed for any shared or production environment:

| Service     | Default                                | Notes                                        |
| ----------- | -------------------------------------- | -------------------------------------------- |
| PostgreSQL  | user `kilocenter`, password `changeme` | Change in `config.yaml` and Docker Compose   |
| MQTT broker | user `admin`, password `KiloCenter`    | Change in Mosquitto config and `config.yaml` |

### TLS for Base Station and Application Center Communication

BSSCI requires TLS 1.2 or higher. SCACI requires TLS 1.3 or higher. These requirements cover the BSSCI and SCACI listeners. They do not establish encryption for internal gRPC, database, cache or web traffic.

#### CA Trust Model

KiloCenter uses a self-signed Certificate Authority (CA) to issue all certificates:

| Certificate        | Purpose                                     | Default Validity | Location                  |
| ------------------ | ------------------------------------------- | ---------------- | ------------------------- |
| CA certificate     | Root of trust; distributed to base stations | 20 years         | `certificates/ca.crt`     |
| CA private key     | Signs server and client certificates        | --               | `certificates/ca.key`     |
| Server certificate | KC-Core BSSCI/SCACI TLS listeners           | 1 year           | `certificates/server.crt` |
| Server private key | TLS handshake                               | --               | `certificates/server.key` |
| Client certificate | Per-base-station mutual TLS                 | 1 year           | Generated on demand       |

Base stations trust the **CA certificate**, not individual server certificates. This means server certificates can be renewed without touching base stations, as long as the same CA signs them.

A base station's client certificate is bound to that station in every edition. A certificate whose common name is a station EUI (`70-B3-D5-9C-D0-00-09-E6`) connects only as that station. The service center pins the fingerprint of the certificate it issued for a station, or, for a station registered without one, of the first certificate that names it; a later certificate with another fingerprint is refused as if the station were not registered. Replacing a station's certificate therefore means issuing the new one through KiloCenter, which stores its fingerprint.

If you regenerate the CA, all existing server and client certificates become invalid and must be reissued. Back up `ca.key` securely.

#### Generating Certificates

**Generate CA + Server Certificates (first-time setup)**

No host Go toolchain required — use the `certgen` compose service:

```bash
docker compose run --rm certgen
```

> **File ownership (Linux):** If generated files are owned by root, rerun with `UID=$(id -u) GID=$(id -g)` prefixed.

For a production FQDN:

```bash
docker compose run --rm --no-deps --entrypoint certgen certgen -dir /app/certificates -days 365 -server bssci.example.com
```

For Docker Compose, the files are in the `cert_data` volume mounted at `/app/certificates`; they are not created in the source tree:

* `ca.crt` and `ca.key` -- CA certificate and private key
* `server.crt` and `server.key` -- server certificate and private key

The server certificate names the `-server` hostname (`localhost` by default), `kilocenter.local`, `127.0.0.1` and `0.0.0.0` as Subject Alternative Names (SANs), plus every name or IP address you pass with `-san`. It never lists the host's network interfaces, so add the hostname or IP address your base stations connect to with `-san`.

**Generate a Client Certificate**

```bash
docker compose run --rm --no-deps --entrypoint certgen certgen \
    -dir /app/certificates -client-only -client 70-B3-D5-9C-D0-00-09-E6
```

**certgen Reference**

| Flag           | Default     | Description                                                           |
| -------------- | ----------- | --------------------------------------------------------------------- |
| `-dir`         | `certs`     | Output directory for certificate files                                |
| `-server`      | `localhost` | Server hostname (used as CN and SAN)                                  |
| `-san`         | (empty)     | Further server names and IP addresses, comma-separated, added as SANs |
| `-days`        | `365`       | Server/client certificate validity in days                            |
| `-ca-years`    | `20`        | CA certificate validity in years                                      |
| `-ca-only`     | `false`     | Generate only the CA certificate                                      |
| `-server-only` | `false`     | Generate only the server certificate (CA must already exist)          |
| `-client-only` | `false`     | Generate only a client certificate (CA must already exist)            |
| `-client`      | (empty)     | Client name for client certificate (e.g., base station EUI)           |

#### Certificate renewal and hostname changes

Use [certificate-only renewal](/kilo-mioty-service-center/security/certificate-renewal.md). Back up the current certificate directory, stop KC-Core, renew with the existing CA, verify the new certificate and hostname, then restart and check reconnections. Keep a matching old server certificate/key pair for rollback. Do not delete data volumes or regenerate the CA for routine server renewal.

**Via GUI** (post-install renewal):

1. Open KC-Web and navigate to **Certificates**.
2. Click **Renew Server Certificates** and confirm.
3. Restart KC-Core to load the new certificates.

**After rotation:**

1. Restart KC-Core to load the new certificates.
2. Verify base station reconnections succeed.
3. If the CA was changed, redistribute `ca.crt` to all base stations.

#### Certificate Configuration

KC-Core loads certificates from paths configured in `config.yaml` (source dev) or `config/config.docker.yaml` (container):

```yaml
protocol:
  bsci_tls:
    enabled: true
    cert_file: "certificates/server.crt"
    key_file: "certificates/server.key"
    ca_file: "certificates/ca.crt"
    min_version: "1.2"
  scaci_tls:
    enabled: true
    cert_file: "certificates/server.crt"
    key_file: "certificates/server.key"
    ca_file: "certificates/ca.crt"
    min_version: "1.3"
```

Paths in source dev mode are relative to the KC-Core working directory. KC-Core will fail to start if these files are missing.

### Network Exposure

Limit which ports are accessible from outside your local network:

| Port  | Service               | Exposure Recommendation                |
| ----- | --------------------- | -------------------------------------- |
| 5000  | BSSCI                 | Only base station networks             |
| 5001  | SCACI                 | Only application center hosts          |
| 9090  | KC-Gateway (gRPC-web) | Operator and API consumer networks     |
| 80    | KC-Web (container)    | Operator networks only                 |
| 50051 | KC-Core internal gRPC | Loopback only, never expose externally |
| 5433  | PostgreSQL            | Loopback only                          |
| 6379  | Redis                 | Loopback only                          |
| 1883  | MQTT                  | Only MQTT consumer networks            |

### Hardening Checklist

* [ ] Rotate all default credentials listed above
* [ ] Restrict network access to management ports (50051, 5433, 6379)
* [ ] Store certificate private keys with restricted file permissions
* [ ] Enable audit-level logging in production environments
* [ ] Review `config.yaml` for any remaining development defaults

### Authentication and edition boundaries

The current Community Edition Docker configuration enables local sign-in in KC-Identity and token validation in KC-Gateway. Authenticate protected API calls through the gateway. The examples omit installation-specific credentials; they do not mean that authentication should be disabled. Keep internal service ports private.

Enterprise features do not mean Community Edition has no authentication. See the [installation safety notice](/kilo-mioty-service-center/security/installation-safety.md) for the remaining default-setting limitations.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.kiloiot.io/kilo-mioty-service-center/security/security-basics.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
