diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..bf20bb5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + public-safety: + name: Public safety + runs-on: ubuntu-24.04 + timeout-minutes: 5 + + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Set up Python 3.12 + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Compile validator + run: python -m py_compile scripts/validate_public_repository.py + + - name: Validate public repository + run: python scripts/validate_public_repository.py diff --git a/.gitignore b/.gitignore index 41e7f38..ba89422 100644 --- a/.gitignore +++ b/.gitignore @@ -7,26 +7,51 @@ desktop.ini .vscode/ .idea/ -# Secrets and private config +# Python +__pycache__/ +*.py[cod] +.venv/ +venv/ + +# Secrets and private configuration *.key *.pem *.p12 *.pfx *.mobileconfig -*.conf.local *.env .env secrets/ private/ keys/ -# WireGuard / VPN real configs +# Authentication and enrollment artifacts +*.authkey +*.tskey +*enrollment*.txt +*enrollment*.png +*qr-code*.png + +# Real WireGuard and VPN configurations wg0.conf *.real.conf *.private.conf +*.conf.local + +# Private Tailscale policy and exports +policy.hujson +tailnet-policy.hujson +tailscale-policy.hujson +tailnet-export*.json +tailscale-export*.json +machines-export*.csv -# Logs +# Raw command output and logs *.log +raw-output/ +connection-test-output/ +admin-console-export/ # Screenshots with potentially sensitive data screenshots/private/ +screenshots/raw/ diff --git a/README.md b/README.md index 5adcb15..5c7fe90 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,139 @@ -# remote-access-network-lab +# Remote Access Network Lab -Documented VPN and remote access learning lab for Windows, macOS and mobile devices. +Documented, public-safe remote-access learning lab for macOS, Windows and mobile clients. ## Purpose -This repository documents a small, security-conscious remote access lab. +This repository documents how trusted devices can reach a personal workstation through a private mesh VPN without exposing SSH or other services directly to the public internet. -The goal is to understand and document how trusted devices can securely reach a personal workstation without exposing unnecessary services directly to the public internet. +The project supports practical learning in: -This project is part of my DataTideHH learning portfolio and supports practical learning in networking, VPN concepts, secure remote access, troubleshooting and technical documentation. +- VPN and remote-access concepts +- device roles and trust boundaries +- SSH over a private network path +- access-control design +- device lifecycle and offboarding +- troubleshooting and technical documentation +- safe publication of infrastructure work -## Lab context +It is a small learning lab, not a production VPN template or an enterprise zero-trust implementation. -The lab environment includes: +## Current verified baseline -- a macOS workstation used as a personal developer machine and intended always-on remote access target -- a Windows 11 school desktop / BBQ OptiPlex Tower used for lab work, documentation, Git/GitHub workflow, Hyper-V and database-related school tasks -- a Windows 11 ThinkPad used as a mobile school / training device and remote access client -- an iPhone 12 Pro Max used as an optional mobile validation client -- VPN-based remote access using Tailscale -- no public secrets, private keys, real IP addresses or sensitive hostnames in this repository +Last validated: **June 2026**. -## Current implementation status +The implemented baseline uses Tailscale as a managed mesh VPN: -The initial Tailscale-based remote access baseline has been tested successfully. +- a personal macOS workstation is the primary remote-access target when powered on, signed in and available +- an institution-managed Windows notebook was used as the tested SSH client +- an institution-managed Windows desktop and an iPhone were enrolled for selected reachability and visibility checks +- enrolled devices were visible in the Tailnet during the recorded test period +- selected device-to-device reachability was verified +- native macOS SSH from the Windows notebook to the macOS workstation over Tailscale was tested successfully +- no public router port forwarding was configured +- Exit Node, Subnet Router, Funnel, Serve and Tailscale SSH were not enabled -Current state: +The recorded tests do not claim permanent availability, unrestricted communication between every device pair or a continuously monitored service. -- Tailscale is installed on the macOS workstation, the BBQ OptiPlex Tower, the BBQ ThinkPad X1 and the iPhone 12 Pro Max. -- All initially intended devices are enrolled in the same Tailnet. -- All devices can see and communicate with each other. -- SSH from the Windows ThinkPad to the macOS workstation over Tailscale was tested successfully. -- No public port forwarding was configured. -- No exit node, subnet router, Funnel, Serve or Tailscale SSH feature was enabled. +## Access-control status -Real Tailscale IP addresses, SSH fingerprints, local network addresses and account-specific details are intentionally omitted. +The repository documents a least-privilege target model, but it does not publish or claim the exact private Tailnet policy currently in use. -## Planned approaches +The intended access path is deliberately narrow: -This lab documents two approaches. +```text +institution-managed Windows client + | + | TCP 22 over Tailscale + v +personal macOS remote-access target +``` + +The target model does not require: + +- general client-to-client access +- access to unrelated personal devices +- subnet routing +- exit-node routing +- public service exposure + +See [Access-control model](docs/access-control-model.md) and the non-functional [example policy](examples/tailnet-policy.example.hujson). + +## Device trust and lifecycle + +Institution-managed school devices are temporary clients, not permanently trusted personal infrastructure. Their use is conditional on organizational permission and continued need. + +They should be reviewed and removed from the Tailnet when: + +- the device is returned or reassigned +- remote access is no longer required +- authorization changes +- the device is lost, compromised or no longer managed as expected + +The documented review includes device approval, key expiry, client updates and offboarding. No real device IDs, hostnames, Tailnet names, account names or authentication material are published. -### 1. Managed mesh VPN approach +## SSH model -A managed mesh VPN solution such as Tailscale provides practical remote access with less operational overhead. +The tested path uses the native macOS OpenSSH service over Tailscale connectivity. Tailscale SSH is not enabled. -This approach is useful for: +Public documentation records only: -- simple device enrollment -- NAT traversal without manual router port forwarding -- controlled access between trusted devices -- day-to-day remote access with low maintenance effort -- avoiding direct exposure of SSH or other services to the public internet +- the source and target roles +- the service and transport path +- the result of the test +- the access boundary -This is the practical approach used for the current working lab baseline. +It does not publish usernames, public keys, fingerprints, passwords or the exact private authentication configuration. A future hardening change should prefer a narrowly authorized account and key-based authentication where practical, but this repository does not claim that such a change has already been implemented. -### 2. Self-managed WireGuard lab +## Managed mesh VPN and WireGuard -WireGuard is included as a technical learning path. +### Current practical baseline -This approach is useful for understanding: +Tailscale is used because it provides private device-to-device connectivity and NAT traversal without public router port forwarding or the operational burden of running a public VPN server on the productive workstation. -- peers -- public and private keys -- AllowedIPs -- endpoints +### Separate learning path + +WireGuard remains a conceptual learning path for: + +- peers and key pairs +- `AllowedIPs` +- endpoint configuration - persistent keepalive - split tunnel versus full tunnel - routing and firewall implications -The productive remote access setup uses the simpler managed approach, while the WireGuard part is treated as a technical learning lab. +The example configuration is intentionally non-functional. No productive WireGuard server is claimed. + +## Public-safety boundary + +This repository must not contain: + +- private keys or authentication tokens +- device enrollment links or QR codes +- real public, private or Tailscale IP addresses +- real hostnames or device-management identifiers +- account names or email addresses used for access control +- SSH fingerprints or authorized-key material +- private Tailnet policy exports +- screenshots containing account, device or infrastructure details +- complete internal network topology + +The repository includes a small Python validation script and GitHub Actions workflow that check for selected high-risk patterns and required public-safety artifacts. + +Run locally: + +```bash +python scripts/validate_public_repository.py +``` ## Repository structure ```text remote-access-network-lab/ +├── .github/workflows/ci.yml ├── README.md ├── docs/ +│ ├── access-control-model.md │ ├── architecture.md │ ├── connection-tests.md │ ├── decision-records/ @@ -87,82 +145,42 @@ remote-access-network-lab/ │ ├── troubleshooting.md │ └── validation-checklist.md ├── diagrams/ -│ ├── .gitkeep │ └── tailscale-topology.md ├── examples/ +│ ├── tailnet-policy.example.hujson │ ├── tailscale-status-example.txt │ └── wireguard-peer-example.conf +├── scripts/ +│ └── validate_public_repository.py ├── .gitignore └── LICENSE ``` -## Network diagram - -The anonymized Tailscale topology is documented here: - -- [Tailscale topology diagram](diagrams/tailscale-topology.md) - -## Learning goals - -- understand VPN-based remote access -- compare managed mesh VPN and self-managed VPN approaches -- document a small network architecture clearly -- practice security-aware configuration documentation -- understand basic routing and access control concepts -- use SSH over a private VPN instead of exposing SSH publicly -- avoid publishing secrets, keys, real public IP addresses or private infrastructure details -- build a small but realistic networking portfolio project - -## Hardware used - -Hardware and operating system details are documented separately: - -- [Hardware and operating systems](docs/hardware.md) - -Sensitive identifiers such as device IDs, product IDs, serial numbers, public IP addresses, private IP addresses, real VPN addresses, SSH fingerprints and authentication material are intentionally omitted. - -## Security principles - -This repository intentionally does not contain: - -- private keys -- real public IP addresses -- real private IP addresses -- real Tailscale IP addresses -- real SSH fingerprints -- VPN enrollment links -- QR codes -- authentication tokens -- screenshots containing private account data -- complete internal network details - -All example configurations are anonymized and non-functional by design. - ## Documentation -The following documents are included: - - [Architecture](docs/architecture.md) -- [Decision record: Managed mesh VPN baseline](docs/decision-records/001-managed-mesh-vpn-baseline.md) -- [Hardware and operating systems](docs/hardware.md) +- [Access-control model](docs/access-control-model.md) +- [Decision record: managed mesh VPN baseline](docs/decision-records/001-managed-mesh-vpn-baseline.md) +- [Hardware and operating-system roles](docs/hardware.md) - [Setup notes](docs/setup-notes.md) - [Connection tests](docs/connection-tests.md) - [Security considerations](docs/security-considerations.md) - [Troubleshooting](docs/troubleshooting.md) - [Portfolio context](docs/portfolio-context.md) - [Validation checklist](docs/validation-checklist.md) +- [Anonymized topology](diagrams/tailscale-topology.md) -## Portfolio and validation +## Current maturity and next review -This repository is intentionally scoped as a small, documented learning lab rather than a production infrastructure template. - -Additional context and review criteria are documented here: - -- [Portfolio context](docs/portfolio-context.md) -- [Validation checklist](docs/validation-checklist.md) +Current maturity: **documented working baseline with explicit public-safety and access-control boundaries**. -## Notes +The next meaningful change should be based on a real review trigger, such as: -This is a learning and documentation project, not a production infrastructure template. +- a new authorized client role +- a verified private least-privilege policy change +- a dedicated gateway or lab host +- subnet routing or exit-node evaluation +- a new dated connection test +- retirement or return of an institution-managed device -The focus is on clear documentation, careful handling of sensitive information and practical understanding of remote access concepts. +Complexity should not be added solely to make the repository look larger. \ No newline at end of file diff --git a/diagrams/tailscale-topology.md b/diagrams/tailscale-topology.md index ea6ce43..8662e40 100644 --- a/diagrams/tailscale-topology.md +++ b/diagrams/tailscale-topology.md @@ -1,33 +1,51 @@ # Tailscale topology diagram -This diagram shows the anonymized remote-access topology used in the lab. +This diagram shows the public-safe device roles and recorded remote-access paths. -No real Tailscale IP addresses, private LAN addresses, SSH fingerprints or account-specific details are included. +Last validated: **June 2026**. + +No real Tailnet names, IP addresses, hostnames, account names, SSH fingerprints or organization-specific device identifiers are included. ```mermaid flowchart LR - subgraph Clients["Trusted client devices"] - TP["Windows ThinkPad X1
mobile client"] - OP["Windows school desktop
BBQ OptiPlex Tower"] - IP["iPhone 12 Pro Max
mobile validation"] + subgraph Clients["Authorized or temporary client roles"] + MW["WINDOWS_MOBILE_CLIENT
institution-managed, temporary"] + WD["WINDOWS_LAB_DESKTOP
institution-managed, selected test"] + IP["MOBILE_VALIDATION_CLIENT
personal mobile device"] end - TS["Tailscale Tailnet
private mesh VPN"] - IM["macOS workstation
iMac remote access target"] + TS["Private Tailnet
managed mesh VPN"] + IM["MACOS_REMOTE_TARGET
personal workstation when available"] - TP --> TS - OP --> TS + MW --> TS + WD --> TS IP --> TS TS --> IM - TP -. "tested: SSH over Tailscale" .-> IM - OP -. "tested: Tailscale reachability" .-> IM + MW -. "tested: native SSH / TCP 22" .-> IM + IM -. "tested: Tailscale ping" .-> WD ``` +## Interpretation + +- the arrows into the Tailnet show enrollment during the recorded test period +- the dashed arrows show specific tested paths +- enrollment does not imply unrestricted traffic between every device pair +- the exact private access policy is not published +- the target least-privilege model requires only TCP 22 from the approved Windows client role to the macOS target + ## Current baseline -- All intended devices were enrolled in the same Tailnet. -- Device-to-device reachability was confirmed. -- SSH from the Windows ThinkPad to the macOS workstation was tested successfully. -- No public port forwarding was configured. -- No exit node, subnet router, Funnel, Serve or Tailscale SSH feature was enabled. +- selected devices were visible in the Tailnet during the recorded test period +- selected Tailscale reachability was confirmed +- native SSH from the Windows mobile client to the macOS target was tested successfully +- no public port forwarding was configured +- no exit node, subnet router, Funnel, Serve or Tailscale SSH feature was enabled + +## Trust boundary + +Institution-managed devices are temporary clients whose enrollment depends on organizational permission and continued need. They should be removed or disabled when returned, reassigned, lost, compromised or no longer authorized. + +## Availability boundary + +The macOS target is a personal productive workstation. It is reachable only when powered on, connected, signed in where required and running the relevant services. The topology does not represent an availability commitment. diff --git a/docs/access-control-model.md b/docs/access-control-model.md new file mode 100644 index 0000000..2a14eed --- /dev/null +++ b/docs/access-control-model.md @@ -0,0 +1,132 @@ +# Access-control model + +## Status + +This document defines the intended public-safe access model for the current remote-access lab. + +It does not publish the private Tailnet policy and does not claim that every rule below is already deployed exactly as written. Private implementation must be verified separately before use. + +## Security objective + +The remote-access path should provide only the access required for the documented use case: + +```text +approved Windows client -> macOS target -> native SSH on TCP 22 +``` + +The model should not create general lateral access between all enrolled devices. + +## Device roles + +| Public role | Trust context | Intended access | +|---|---|---| +| `remote-target` | Personal macOS workstation | Receives narrowly scoped remote administration traffic when available | +| `managed-client` | Institution-managed Windows device used temporarily with permission | May initiate only the approved remote-access flow | +| `mobile-validation` | Personal mobile device | Connectivity validation only unless a separate need is documented | +| `unrelated-device` | Other personal or lab endpoint | No access implied by this project | + +Real hostnames, user identities, tags and device IDs are private and must not be copied into this repository. + +## Intended grants + +The public target model permits: + +- approved `managed-client` devices to reach `remote-target` on TCP 22 +- administrative control-plane actions only by the private Tailnet administrator + +The public target model does not require: + +- arbitrary ports from the managed client to the target +- access from the target back to the managed client +- managed-client access to unrelated devices +- mobile-client access to SSH +- client-to-client traffic +- subnet routes +- exit-node routes +- public ingress through Funnel or Serve + +Rules should be deny-by-omission: traffic is not granted unless the documented use case requires it. + +## Policy implementation boundary + +Tailscale supports policy-based access control. The current public example uses role tags and a `grants` rule because this expresses the intended source, destination and network capability without publishing real identities. + +The example under `examples/tailnet-policy.example.hujson` is deliberately non-functional: + +- it uses generic role tags +- it contains no real users or devices +- it is not an export from the private Tailnet +- it must be reviewed in the private environment before any adaptation + +## Device approval and key lifecycle + +The private Tailnet review should answer: + +1. Is device approval enabled or otherwise handled deliberately? +2. Who may approve a new device? +3. Is the device still authorized and required? +4. Is key expiry enabled and appropriate for the role? +5. Is the client software current? +6. Has a returned, lost or reassigned device been removed promptly? + +Institution-managed devices should not receive indefinite trust merely because they were enrolled successfully once. + +## Institution-managed device boundary + +A school-managed device may be used only when: + +- installation and remote-access use are permitted by the organization +- the device remains under expected management controls +- the access is needed for the documented learning use case +- no organizational data or credentials are copied into the personal lab + +The device must be removed or disabled when it is returned, reassigned, lost, no longer authorized or no longer needed. + +## SSH boundary + +The tested service is native macOS OpenSSH carried over Tailscale connectivity. Tailscale SSH is not enabled. + +Public documentation should record: + +- source role +- target role +- TCP port 22 +- test result and validation date +- whether public port forwarding was absent + +Public documentation must not record: + +- login names +- passwords +- public or private keys +- SSH fingerprints +- complete `sshd_config` output +- authorized-key files + +A private hardening review should prefer the narrowest practical authorized account and key-based authentication. This is a target recommendation, not an implementation claim. + +## Offboarding procedure + +When a client is no longer trusted or required: + +1. disable or remove the device from the Tailnet +2. revoke any relevant authentication material +3. review grants, groups and tags for stale references +4. remove local SSH authorization if it was dedicated to that client +5. record only an anonymized offboarding result in public documentation +6. revalidate the remaining intended access path + +## Review triggers + +Review this model before adding: + +- another user or device category +- broader port access +- subnet routing +- an exit node +- Tailscale SSH +- Funnel or Serve +- a dedicated gateway +- a WireGuard server +- automation using authentication keys +- access from devices outside the trusted personal or authorized institutional scope diff --git a/docs/architecture.md b/docs/architecture.md index 6f5d17e..a686431 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -2,64 +2,115 @@ ## Overview -This lab documents secure remote access between trusted personal devices. +This lab documents a narrow remote-access path between trusted or explicitly authorized devices. -The main design goal is to avoid exposing a personal workstation directly to the public internet while still allowing controlled access from trusted clients. +The design goal is to reach a personal macOS workstation without exposing SSH directly to the public internet and without treating every enrolled device as equally or permanently trusted. -The current practical baseline uses Tailscale as a managed mesh VPN. WireGuard is kept as a separate learning path for understanding lower-level VPN concepts. +The current practical baseline uses Tailscale as a managed mesh VPN. WireGuard remains a separate learning path for lower-level VPN concepts. -## Conceptual topology +Last validated: **June 2026**. + +## Public-safe topology ```mermaid flowchart LR - TP["Windows ThinkPad X1
mobile client"] --> TS["Tailscale Tailnet
private mesh VPN"] - OP["Windows school desktop
BBQ OptiPlex Tower"] --> TS - IP["iPhone 12 Pro Max
mobile validation client"] --> TS - TS --> IM["macOS workstation
iMac remote access target"] - TP -. "SSH over Tailscale" .-> IM + MW["Institution-managed Windows notebook
temporary remote client"] + WD["Institution-managed Windows desktop
selected reachability test"] + IP["Personal mobile device
optional visibility test"] + TS["Private Tailnet
managed mesh VPN"] + IM["Personal macOS workstation
remote target when available"] + + MW --> TS + WD --> TS + IP --> TS + TS --> IM + + MW -. "tested: native SSH / TCP 22" .-> IM + WD -. "tested: selected Tailscale reachability" .-> IM ``` +The diagram shows enrolled roles and recorded test paths. It does not imply unrestricted communication among every device pair. + ## Device roles -| Role | Device type | Purpose | +| Role | Trust context | Purpose | |---|---|---| -| Target system | macOS workstation | Personal developer machine and intended always-on remote access target | -| Windows lab machine | BBQ OptiPlex Tower | School desktop, lab work, Git/GitHub workflow, Hyper-V and database-related tasks | -| Mobile Windows client | BBQ ThinkPad X1 | Mobile school/training device and remote access client | -| Mobile validation client | iPhone 12 Pro Max | Optional mobile connectivity validation | -| VPN layer | Tailscale Tailnet | Private device-to-device connectivity without public port forwarding | +| Personal remote target | macOS workstation | Developer workstation reachable only when powered on, signed in and available | +| Temporary managed client | Institution-managed Windows notebook | Authorized remote-access client for the documented SSH test | +| Managed lab workstation | Institution-managed Windows desktop | Selected reachability and school-context lab validation | +| Mobile validation client | Personal mobile device | Optional Tailnet visibility or connectivity check | +| Connectivity layer | Tailscale Tailnet | Private device-to-device transport without public port forwarding | + +Institution-managed devices are not treated as permanent personal infrastructure. Their authorization and continued need must be reviewed. + +## Access path + +The intended minimal path is: + +```text +approved managed client + | + | Tailscale transport + | native SSH / TCP 22 + v +personal macOS target +``` + +The design does not require: + +- client-to-client access +- access to unrelated personal systems +- subnet routing +- exit-node routing +- public ingress +- Tailscale SSH -## Approach A: Managed mesh VPN +See [Access-control model](access-control-model.md). -A managed mesh VPN can simplify: +## Managed mesh VPN decision -- device enrollment +The managed approach is preferred for the current practical baseline because it reduces operational complexity while supporting: + +- authenticated device enrollment - NAT traversal -- identity-based access -- key distribution +- private addressing +- policy-based access control +- cross-platform operation - remote access without router port forwarding -- practical operation across macOS, Windows and iOS -This is the preferred practical approach for daily use in this lab. +The exact private Tailnet policy is not published. -## Approach B: WireGuard lab +## WireGuard learning path -A WireGuard setup is useful for learning: +WireGuard remains useful for understanding: -- peers -- key pairs -- AllowedIPs -- endpoint configuration +- peers and key pairs +- `AllowedIPs` +- endpoints - persistent keepalive -- split tunnel versus full tunnel +- split and full tunnels - routing and firewall implications -This approach is treated as a technical lab and should not expose sensitive production systems without a clear security model. +No productive WireGuard server or public VPN endpoint is claimed. + +## Availability boundary + +The macOS workstation is a productive personal endpoint, not a server with an availability commitment. Remote access depends on: -## Design decision +- power state +- an active user session where required +- network connectivity +- Tailscale client state +- native SSH service state +- local access permissions -For productive use, the safer and simpler managed approach is preferred. +## Repository boundaries -For technical understanding, the WireGuard approach is documented separately as a learning exercise. +This repository documents architecture, decisions, anonymized validation and public-safety rules. It does not publish: -The macOS workstation is treated as a productive endpoint, not as a general-purpose public server. +- real hostnames or addresses +- a private Tailnet export +- account identities +- keys or fingerprints +- organization-specific device-management data +- complete internal topology diff --git a/docs/connection-tests.md b/docs/connection-tests.md index dd57192..aafa1f4 100644 --- a/docs/connection-tests.md +++ b/docs/connection-tests.md @@ -1,75 +1,109 @@ # Connection tests -This document records anonymized connection test results. +This document records anonymized results from the initial validation period. -Real Tailscale IP addresses, SSH fingerprints, local network addresses and account-specific details are intentionally omitted. +Last validated: **June 2026**. -## Test 1: macOS workstation to Windows school desktop +Real addresses, hostnames, account names, fingerprints and Tailnet identifiers are intentionally omitted. + +## Test summary + +| Validation period | Source role | Target role | Test | Result | Observed path | +|---|---|---|---|---|---| +| June 2026 | Personal macOS target | Institution-managed Windows desktop | Tailscale ping | Passed | DERP relay observed during the recorded test | +| June 2026 | Institution-managed Windows notebook | Personal macOS target | Native SSH over Tailscale, TCP 22 | Passed | Private Tailnet path; no public port forwarding | +| June 2026 | Enrolled test devices | Tailnet control plane | Device visibility | Passed | Devices visible during the recorded test period | + +These tests demonstrate selected reachability paths. They do not prove unrestricted communication between all device pairs, permanent online status or a continuously monitored service level. + +## Test 1: selected Tailscale reachability | Field | Result | |---|---| -| Source | macOS workstation | -| Target | Windows school desktop / BBQ OptiPlex Tower | +| Source | Personal macOS remote target | +| Target | Institution-managed Windows desktop | | Method | Tailscale ping | | Result | Successful | -| Path | Relay path observed during initial test | -| Notes | Direct peer-to-peer connectivity was not established during the first test, which is acceptable for the initial working state. | +| Path | DERP relay observed during this test | +| Interpretation | Private reachability existed; a direct peer-to-peer path was not established at that moment | Anonymized observation: ```text -tailscale ping windows-school-desktop -pong from windows-school-desktop via DERP relay -direct connection not established +tailscale ping WINDOWS_LAB_DESKTOP +pong from WINDOWS_LAB_DESKTOP via DERP relay ``` -## Test 2: Windows ThinkPad to macOS workstation via SSH +A relay path is a valid connectivity result, but it may differ on another network or date. + +## Test 2: SSH over Tailscale | Field | Result | |---|---| -| Source | Windows ThinkPad X1 | -| Target | macOS workstation | -| Method | SSH over Tailscale | +| Source | `WINDOWS_MOBILE_CLIENT` | +| Target | `MACOS_REMOTE_TARGET` | +| Method | Native SSH over Tailscale | +| Port | TCP 22 | | Result | Successful | | Public port forwarding | Not used | -| macOS Remote Login | Enabled | -| Access scope | Admin users only | +| macOS Remote Login | Enabled for the private test | +| Tailscale SSH | Not enabled | -Anonymized command: +Anonymized command pattern: ```text -ssh user@example-macos-workstation +ssh @MACOS_REMOTE_TARGET ``` Anonymized result: ```text -Login successful. +Authentication completed. Remote shell opened on the macOS workstation. ``` -## Test 3: Device visibility +The actual user name, authentication method, host key and fingerprint are private and are not recorded here. + +## Test 3: Tailnet visibility -| Device role | Tailnet visibility | +| Public device role | Visibility during recorded test | |---|---| -| macOS workstation | Visible | -| Windows school desktop | Visible during initial test | -| Windows ThinkPad X1 | Visible | -| iPhone 12 Pro Max | Visible | +| Personal macOS target | Visible | +| Institution-managed Windows desktop | Visible | +| Institution-managed Windows notebook | Visible | +| Personal mobile validation device | Visible | + +Visibility does not itself authorize every service or direction of traffic. Access control must be evaluated separately. + +## Availability notes + +The institution-managed desktop may become unavailable due to power management, network policy, reassignment or organizational controls. + +The personal macOS workstation may be unavailable when powered off, signed out where a user session is required, sleeping, disconnected or not running the required services. + +These conditions are expected for a personal learning lab and are not treated as failures of a guaranteed service. -## Notes +## Revalidation procedure -The Windows school desktop may go offline after the user session is locked or when school-network power management takes effect. +A future test record should include: -This is acceptable for the current lab state because the primary remote access use case is the Windows ThinkPad connecting to the macOS workstation at home. +1. validation month or date +2. source and target role names +3. tested service and port +4. pass/fail result +5. whether a direct or relay path was observed +6. whether public port forwarding remained absent +7. whether the device was still authorized +8. only anonymized output ## Publication rule Do not publish: -- real Tailscale IP addresses -- SSH fingerprints -- private LAN addresses -- real account names -- authentication prompts -- VPN enrollment links +- real Tailscale, LAN or public IP addresses +- real hostnames or Tailnet names +- account names or email addresses +- SSH fingerprints, keys or authentication prompts +- enrollment links or QR codes +- raw admin-console screenshots +- complete internal topology diff --git a/docs/decision-records/001-managed-mesh-vpn-baseline.md b/docs/decision-records/001-managed-mesh-vpn-baseline.md index 243a78e..5d30530 100644 --- a/docs/decision-records/001-managed-mesh-vpn-baseline.md +++ b/docs/decision-records/001-managed-mesh-vpn-baseline.md @@ -4,94 +4,127 @@ Accepted for the current learning lab baseline. -## Context +Last reviewed: **July 2026**. -This lab documents remote access between trusted personal devices. +## Context -The practical requirement is to reach a personal macOS workstation securely from trusted clients without exposing SSH or other services directly to the public internet. +The practical requirement is to reach a personal macOS workstation from an authorized client without exposing SSH or other services directly to the public internet. -The lab also has a learning goal: understanding VPN concepts, remote access design, security boundaries, troubleshooting and technical documentation. +The lab also supports learning in VPN concepts, remote-access design, access control, device lifecycle, troubleshooting and public-safe technical documentation. Two approaches are relevant: -- a managed mesh VPN approach using Tailscale -- a self-managed WireGuard approach as a technical learning path +- managed mesh VPN using Tailscale for the practical baseline +- self-managed WireGuard as a separate technical learning path ## Decision -The current practical baseline uses Tailscale as the managed mesh VPN layer. +Use Tailscale as the private connectivity layer for the current practical baseline. -WireGuard remains included as a separate learning path, but not as the productive baseline for this lab. +Use native macOS OpenSSH over the Tailnet for the recorded remote shell test. Do not enable Tailscale SSH as part of this baseline. -The current baseline does not enable: +Do not enable: - public router port forwarding - Exit Node - Subnet Router - Funnel - Serve -- Tailscale SSH +- public WireGuard server operation + +Treat institution-managed Windows devices as temporary, authorization-dependent clients rather than permanent personal infrastructure. -SSH access to the macOS workstation is tested only over the private Tailnet. +Document a least-privilege target model in which the approved client role requires only TCP 22 access to the macOS target. Do not publish the exact private Tailnet policy. ## Rationale -Tailscale is appropriate for the current baseline because it reduces operational complexity while still supporting the main learning and access goals. +The managed mesh approach: -The managed mesh VPN approach provides: +- avoids public SSH exposure +- provides NAT traversal without manual router configuration +- supports macOS, Windows and iOS +- reduces the operational burden on the productive workstation +- supports policy-based restrictions +- is easier to validate and revoke than an improvised public VPN service -- simple device enrollment -- NAT traversal without manual router configuration -- private connectivity between trusted devices -- lower maintenance effort for a personal learning lab -- a safer default posture than exposing SSH directly to the public internet -- a realistic remote access setup across macOS, Windows and iOS devices +WireGuard remains valuable for learning peers, keys, `AllowedIPs`, endpoints, routing and firewall behavior, but that learning objective does not justify operating a public VPN server on the personal workstation. -WireGuard remains valuable for learning because it exposes lower-level VPN concepts such as peers, key pairs, AllowedIPs, endpoints, persistent keepalive, routing and firewall implications. +## Consequences -For this lab, the safer practical choice is to use the managed approach for daily remote access and to keep WireGuard as a separate technical exercise. +### Positive -## Consequences +- no public SSH port is required +- the remote-access path is small and explainable +- connectivity and authorization can be considered separately +- device roles and trust boundaries are explicit +- temporary clients can be offboarded +- public examples can remain synthetic + +### Trade-offs + +- the solution depends on an external provider account and control plane +- lower-level WireGuard mechanics are abstracted +- private policy state must be reviewed outside the public repository +- device approval, key expiry and offboarding require ongoing administration +- the personal workstation has no availability commitment -Positive consequences: +## Access-control consequence -- the lab has a working and understandable remote access baseline -- no public SSH exposure is required -- the setup is easier to document and validate -- the device roles remain clear -- sensitive infrastructure details can stay anonymized -- the lab stays small enough to reason about +Enrollment alone must not be interpreted as unrestricted authorization. -Trade-offs: +The target model grants only the required client-to-target service and does not require: -- some lower-level VPN mechanics are abstracted away by the managed service -- the setup depends on an external provider account and control plane -- advanced routing scenarios are intentionally not part of the current baseline -- this is not a complete enterprise remote access architecture +- general client-to-client access +- access to unrelated personal devices +- subnet or exit-node routing +- mobile SSH access +- all-port connectivity -## Security notes +See [Access-control model](../access-control-model.md). -The current baseline intentionally keeps the reachable service set small. +## Institution-managed device consequence -The following items must not be published: +Use of school-managed endpoints is conditional on organizational permission and continued need. -- private keys -- authentication tokens -- VPN enrollment links -- real public IP addresses -- real private IP addresses -- real Tailscale IP addresses -- real SSH fingerprints -- complete internal network details +Return, reassignment, loss, compromise or withdrawal of authorization requires prompt removal or disabling of the device and review of related access. -## Review trigger +## SSH consequence -This decision should be reviewed if the lab later adds: +The repository may document the tested role-to-role path and TCP port, but it must not publish: -- a dedicated gateway device +- real login names +- authentication secrets +- public or private keys +- SSH fingerprints +- complete SSH configuration + +A future private hardening review should prefer the narrowest practical account scope and key-based authentication where practical. This is a recommendation, not a current implementation claim. + +## Public-safety consequence + +Do not publish: + +- private keys, auth keys or tokens +- enrollment links or QR codes +- real public, private or Tailscale addresses +- real hostnames, account names or Tailnet names +- device-management identifiers +- private policy exports +- raw admin-console screenshots +- complete internal topology + +## Review triggers + +Review this decision before adding: + +- another user or device trust category +- broader port access +- a dedicated gateway - subnet routing -- exit node functionality +- exit-node functionality +- Tailscale SSH +- Funnel or Serve - public service exposure - WireGuard server operation -- a Raspberry Pi, router, Linux VM or VPS as a VPN endpoint -- broader access for devices beyond the trusted personal lab environment +- automation using authentication keys +- devices outside the trusted personal or explicitly authorized institutional scope diff --git a/docs/hardware.md b/docs/hardware.md index 9c347f9..f6677e4 100644 --- a/docs/hardware.md +++ b/docs/hardware.md @@ -1,109 +1,95 @@ -# Hardware and operating systems +# Hardware and operating-system roles -This document lists the hardware and operating systems used or planned for this remote access network lab. +This document records only the hardware characteristics needed to explain the lab architecture. Real hostnames, asset identifiers, serial numbers, product IDs, VPN addresses, account names and organization-specific management details are intentionally excluded. -Sensitive identifiers such as Windows device IDs, product IDs, serial numbers, personal account names, public IP addresses, private IP addresses, VPN addresses and real hostnames are intentionally omitted or anonymized. +## Personal macOS workstation -## macOS workstation: personal iMac - -| Category | Value | +| Category | Public-safe value | |---|---| -| Role | Personal macOS workstation / intended always-on remote access target | +| Role | Personal developer workstation and primary remote-access target when available | | Device class | Apple iMac Retina 4K, 21.5-inch, Late 2015 | -| Model identifier | iMac16,2 | +| Model identifier | `iMac16,2` | | CPU architecture | Intel x86_64 | | Operating system | macOS Sonoma via OpenCore Legacy Patcher | -| Usage context | Learning, development, GitHub portfolio work and personal lab environment | -| Notes | Productive developer workstation. Should not be treated as a general-purpose public server. | +| Usage context | Development, portfolio work and personal lab activity | +| Availability boundary | Reachable only when powered on, signed in where required, connected and running the required services | +| Security boundary | Productive endpoint; not a general-purpose public server | + +The model and architecture are relevant to reproducibility. The real hostname, addresses, account name, SSH fingerprints and device serial number are not. -## Windows lab machine: BBQ school desktop +## Institution-managed Windows desktop -| Category | Value | +| Category | Public-safe value | |---|---| -| Role | Windows lab machine / school desktop | -| Device name | BBQ-BM6HJ64 | -| Device class | Desktop PC | -| CPU | Intel Core i5-14500 | -| Base clock | 2.60 GHz | -| Installed RAM | 32.0 GB | -| Usable RAM | 31.7 GB | -| System type | 64-bit operating system, x64-based processor | -| Pen and touch | No pen or touch input available | +| Public role name | `WINDOWS_LAB_DESKTOP` | +| Role | School-context Windows lab workstation | +| Device class | x86_64 desktop PC | +| Processor class | Modern Intel Core desktop processor | +| Memory class | 32 GB RAM | | Operating system | Windows 11 Enterprise | -| Version | 25H2 | -| Installed on | 2026-04-07 | -| OS build | 26200.8390 | -| Windows Feature Experience Pack | 1000.26100.297.0 | -| Usage context | Windows-based testing, Git/GitHub workflow, documentation work, Hyper-V and school-context lab tasks | +| Usage context | Selected connectivity tests, Git/GitHub work, documentation, virtualization and database-related school tasks | +| Trust boundary | Institution-managed, temporary and authorization-dependent | -## Windows mobile lab machine: BBQ ThinkPad X1 Carbon Gen 9 +The repository deliberately omits the real device name, asset identifiers, exact OS build, installation date, firmware versions and management-policy details because they are not required to understand the remote-access architecture. -| Category | Value | +## Institution-managed Windows notebook + +| Category | Public-safe value | |---|---| -| Role | Windows mobile lab machine / BBQ school notebook | -| Device name | BBQEDU-PF3NRBA0 | -| Manufacturer | Lenovo | -| Model | ThinkPad X1 Carbon Gen 9 | -| System model | 20XXS24W00 | -| System SKU | LENOVO_MT_20XX_BU_Think_FM_ThinkPad X1 Carbon Gen 9 | -| Device class | Notebook | -| Platform role | Mobile | -| CPU | 11th Gen Intel Core i7-1185G7 | -| CPU base clock | 3.00 GHz | -| CPU details | 4 cores, 8 logical processors | -| Installed RAM | 16.0 GB | -| Total physical memory | 15.7 GB | -| Page file | 8.00 GB, C:\pagefile.sys | -| System type | x64-based PC | +| Public role name | `WINDOWS_MOBILE_CLIENT` | +| Role | Mobile school-context client used for the recorded SSH test | +| Device class | Lenovo ThinkPad X1 Carbon Gen 9 | +| Processor class | 11th-generation Intel Core i7, x86_64 | +| Memory class | 16 GB RAM | | Operating system | Windows 11 Enterprise | -| OS version | 10.0.26200 Build 26200 | -| BIOS mode | UEFI | -| BIOS version/date | Lenovo N32ETA1W (1.77), 2026-02-18 | -| SMBIOS version | 3.2 | -| Embedded controller version | 1.37 | -| Secure Boot state | Off | -| Kernel DMA Protection | On | -| Virtualization-based security | Running | -| Running VBS services | Credential Guard, Hypervisor-enforced Code Integrity, Secure Launch, SMM Firmware Measurement, Kernel-mode Hardware-enforced Stack Protection | -| App Control for Business policy | Enforced | -| App Control for Business user-mode policy | Off | -| SMM isolation level | Firmware Protection Version 2 | -| Hypervisor status | Hypervisor detected | -| Usage context | Mobile Windows test client, school-context device, remote access client, Git/GitHub verification, documentation and networking practice | - -## Relevance for this lab - -The lab intentionally includes different device types and operating systems: - -- macOS as the intended always-on target system -- Windows desktop as a school/lab workstation -- Windows notebook as a mobile client system -- optional mobile device testing later - -This allows the project to document remote access and VPN behavior across realistic mixed environments. - -## Security and privacy notes - -The following values are intentionally not included in this public repository: - -- Windows device IDs -- Windows product IDs -- serial numbers -- personal account names -- public IP addresses -- private LAN IP addresses -- VPN-assigned real IP addresses -- private hostnames -- authentication material -- SSH keys -- VPN keys -- tokens -- screenshots containing private account or infrastructure details +| Usage context | Mobile remote-access client, Git/GitHub verification, documentation and networking practice | +| Trust boundary | Institution-managed, temporary and authorization-dependent | + +The repository does not publish the real hostname, model serial, system SKU, BIOS version, exact build number or detailed endpoint-management state. + +## Personal mobile validation device + +| Category | Public-safe value | +|---|---| +| Public role name | `MOBILE_VALIDATION_CLIENT` | +| Device class | Personal iPhone | +| Operating-system family | iOS | +| Usage context | Optional Tailnet visibility and connectivity validation | +| Trust boundary | Personal device; no SSH permission implied by this role | -## Operational notes +The exact VPN address, account identity and device-management identifiers are excluded. -The macOS workstation is the intended always-on endpoint, but it should not be exposed directly to the public internet. +## Why mixed platforms matter -For practical daily use, a managed mesh VPN approach may be preferred. +The lab intentionally spans: -For technical learning, a separate WireGuard lab can be documented to understand peers, key pairs, AllowedIPs, routing, split tunneling and firewall implications. +- macOS as the remote target +- Windows as the tested remote client and school-context workstation +- iOS as an optional mobile validation platform + +This supports cross-platform troubleshooting without turning hardware inventory into an unnecessary disclosure of device-management data. + +## Institution-managed device conditions + +An institution-managed device may participate only while: + +- installation and use are permitted +- the device is still needed for the documented lab purpose +- organizational and personal data remain separated +- the device remains under expected management controls +- the Tailnet enrollment is reviewed and removed during offboarding + +Return, reassignment, loss, compromise or withdrawal of authorization is an immediate review trigger. + +## Information excluded from the public repository + +- real hostnames +- asset tags and device IDs +- serial numbers and product IDs +- exact VPN and LAN addresses +- account identities +- authentication material +- SSH keys and fingerprints +- private Tailnet tags and policy exports +- exact Windows installation dates and volatile build metadata +- detailed organization-specific security-policy configuration diff --git a/docs/portfolio-context.md b/docs/portfolio-context.md index 9084827..44818cf 100644 --- a/docs/portfolio-context.md +++ b/docs/portfolio-context.md @@ -2,63 +2,91 @@ ## Why this project exists -This repository documents a small remote access and VPN learning lab. +This repository documents a small remote-access and VPN learning lab with an emphasis on security boundaries, device lifecycle and public-safe technical evidence. -The goal is not to present a production-ready enterprise VPN architecture. Instead, the project shows how a security-conscious remote access setup can be planned, tested and documented in a realistic personal learning environment. +The goal is not to present a production-ready enterprise VPN architecture. The project shows how a practical access path can be selected, tested, limited and documented without publishing private infrastructure details. -The current baseline uses Tailscale as a managed mesh VPN between trusted devices. WireGuard is included as a separate learning path for understanding lower-level VPN concepts. +## What is implemented -## What this project demonstrates +The recorded baseline uses Tailscale as a managed mesh VPN between selected trusted or authorized devices. + +Validated in June 2026: + +- selected device visibility in the Tailnet +- selected Tailscale reachability +- native SSH from an institution-managed Windows notebook to a personal macOS workstation +- no public router port forwarding +- no Exit Node, Subnet Router, Funnel, Serve or Tailscale SSH -This project demonstrates practical understanding of: +The repository does not claim unrestricted communication between all devices, continuous availability or a published production policy. -- VPN-based remote access -- secure access to a workstation without public port forwarding -- device roles in a small network environment -- SSH over a private VPN -- documentation of technical assumptions and limitations -- anonymization of sensitive infrastructure details -- basic operational validation through connection tests +## What this project demonstrates + +- remote access without public SSH exposure +- difference between connectivity and authorization +- explicit device roles and trust boundaries +- native SSH over a private mesh VPN +- access-control modelling +- temporary trust for institution-managed devices +- key-expiry, approval and offboarding considerations +- dated and anonymized connection evidence +- conservative handling of infrastructure details +- decision records and troubleshooting logic -## Relation to my learning path +## Relation to the Data and Process Analysis path -This lab supports my Fachinformatiker Daten- und Prozessanalyse learning path by connecting networking fundamentals with documentation, troubleshooting and structured technical reasoning. +The project complements the main Data/BI portfolio by demonstrating supporting IT foundations: -It complements data and BI-focused projects by showing the infrastructure side of practical IT work: +- how operational systems are reached securely +- how technical access paths are modelled +- how assumptions and controls are documented +- how device lifecycle becomes a repeatable process +- how validation evidence is separated from sensitive raw data +- how risks and limitations are communicated clearly -- how systems are reached securely -- how access paths are documented -- how network assumptions are made explicit -- how technical risks are limited and communicated -- how lab results are recorded without exposing private details +It supports the broader profile without claiming a separate specialization in network engineering or cybersecurity. ## Scope boundaries -This repository intentionally does not claim to be: +This repository is not: - a production VPN template -- a complete zero trust architecture -- a full firewall or routing design -- an enterprise remote access implementation -- a replacement for professional security review - -The current scope is a small, realistic learning lab with clear documentation and conservative security assumptions. +- a complete zero-trust architecture +- a firewall or routing design +- a public WireGuard service +- an enterprise identity architecture +- a continuously monitored remote-access service +- a substitute for organizational authorization or professional security review -## Current maturity level +## Current maturity -Current maturity level: documented working lab baseline. +Current maturity: **documented working baseline with explicit public-safety, access-control and offboarding boundaries**. -The Tailscale-based setup has been validated for device visibility and SSH access between trusted devices. Further work should stay incremental and should avoid adding unnecessary complexity before the current baseline is fully documented and reviewed. +The technical baseline is intentionally small. Further work should be triggered by a real need or a verified architecture change, not by a desire to add more tools. ## Portfolio value -The value of this project is not the amount of code. - The value is the ability to explain: -- what was built -- why a managed VPN approach was chosen -- what was deliberately not enabled -- how the setup was validated -- which sensitive details must not be published -- what would be required before treating a similar setup as production infrastructure +- which access problem was solved +- why a managed mesh VPN was chosen +- what was tested and when +- what the tests do and do not prove +- which features were deliberately excluded +- how access should be limited +- how institution-managed clients are offboarded +- which information must remain private +- what would require a new security review + +## Appropriate next milestones + +A future milestone would be justified by one of these events: + +- a newly authorized client role +- a privately verified least-privilege policy change +- a new dated connection test +- removal or return of an institution-managed device +- a dedicated gateway or lab host +- evaluation of subnet routing or an exit node + +Until then, the current baseline should remain stable and easy to review. diff --git a/docs/security-considerations.md b/docs/security-considerations.md index dae8fe0..17c9f4f 100644 --- a/docs/security-considerations.md +++ b/docs/security-considerations.md @@ -2,66 +2,146 @@ ## Main principle -Remote access must be useful, but it must not unnecessarily increase the attack surface of the home network or personal workstation. +Remote access must solve a specific access need without creating unnecessary exposure, lateral movement or permanent trust. -## Current security posture +## Current verified posture -The current setup uses Tailscale as a private connectivity layer between trusted devices. +Last validated: **June 2026**. -No public router port forwarding was configured. +The recorded baseline used Tailscale as a private connectivity layer between selected trusted or authorized devices. -The macOS workstation is reachable over Tailscale for SSH after Remote Login was enabled. +Verified properties: -## Features not enabled +- no public router port forwarding was configured +- the macOS workstation was reachable through Tailscale for native SSH after Remote Login was enabled +- SSH from the institution-managed Windows notebook to the macOS target succeeded +- selected Tailscale reachability and Tailnet visibility checks succeeded +- Exit Node, Subnet Router, Funnel, Serve and Tailscale SSH were not enabled -The following features were intentionally not enabled during the initial setup: +These statements describe the recorded test period. They are not a permanent availability or policy-compliance guarantee. +## Trust categories + +Devices are not considered equally trusted merely because they are enrolled in the same Tailnet. + +| Category | Security treatment | +|---|---| +| Personal remote target | Productive endpoint; expose only the required private service | +| Institution-managed client | Temporary, authorization-dependent and subject to offboarding | +| Personal mobile validation device | Visibility testing only unless another need is approved | +| Unrelated device | No access implied by this lab | + +## Access-control principle + +The intended public model is deny-by-omission: + +- grant only the required source-to-destination path +- restrict the service to native SSH on TCP 22 +- do not grant general client-to-client access +- do not grant access to unrelated personal systems +- do not publish the real Tailnet policy + +See [Access-control model](access-control-model.md). + +## Device approval and key lifecycle + +The private administrative review should cover: + +- whether new devices require explicit approval +- who may approve them +- whether key expiry is enabled and appropriate +- whether the client remains current +- whether the device is still needed and authorized +- whether returned, lost, compromised or reassigned devices have been removed + +No device should retain indefinite access solely because its initial enrollment succeeded. + +## Institution-managed devices + +School-managed systems are not permanent personal infrastructure. + +Use is conditional on organizational permission. The lab must not: + +- bypass endpoint-management controls +- copy organizational credentials or data into the personal environment +- create undeclared persistent access +- retain the device in the Tailnet after it is returned or no longer needed + +Offboarding is required when authorization, ownership, assignment or trust changes. + +## Native macOS SSH + +The tested service is native macOS OpenSSH transported over Tailscale. Tailscale SSH is not enabled. + +Public documentation may state: + +- the source and target roles +- TCP port 22 +- whether the test passed +- the validation date +- that public port forwarding was absent + +Public documentation must not include: + +- local login names +- passwords +- private or public keys +- SSH fingerprints +- authorized-key files +- complete SSH configuration output + +A private hardening review should prefer: + +- the narrowest practical authorized account +- key-based authentication where practical +- a clear revocation path +- removal of stale authorization + +These are target controls, not claims that every item is already implemented. + +## Features intentionally outside the baseline + +- public SSH exposure +- Tailscale SSH - Exit Node - Subnet Router - Funnel - Serve -- Tailscale SSH +- public WireGuard server operation +- broader routing to the home network -This keeps the initial lab small and easier to reason about. +Adding any of these requires a separate architecture and security review. -## macOS Remote Login +## Availability boundary -macOS Remote Login was enabled for SSH testing. +The macOS workstation is a personal productive endpoint, not an always-available server. Reachability depends on power state, user session, networking, Tailscale state, SSH service state and local permissions. -Access was limited to admin users. - -SSH is intended to be used only through the private Tailnet, not through public internet exposure. - -## What will not be published +## Public repository exclusions This repository must never contain: -- private keys -- real public IP addresses -- real private IP addresses -- real Tailscale IP addresses -- real SSH fingerprints -- device enrollment links -- QR codes -- authentication tokens -- screenshots with private account data -- complete internal network details - -## Preferred security posture - -- Use VPN-based access instead of exposing SSH directly to the internet -- Use trusted devices only -- Keep the number of reachable services small -- Use least privilege where possible -- Document assumptions and limitations -- Treat the macOS workstation as a productive endpoint, not as a general-purpose public server +- private keys or authentication tokens +- auth keys, enrollment links or QR codes +- real public, private or Tailscale IP addresses +- real hostnames, Tailnet names or account identities +- SSH fingerprints or authorized keys +- private policy exports +- raw admin-console exports +- screenshots with private account or device data +- complete internal topology +- organization-specific asset or management identifiers -## Risk considerations +## Incident and offboarding response -Running a VPN client is low risk when configured correctly. +If a device is lost, compromised, returned, reassigned or no longer authorized: -Running a public VPN server directly on a productive workstation is a higher operational responsibility. For a more professional WireGuard setup, a separate gateway such as a router, Raspberry Pi, Linux VM or VPS may be preferable. +1. disable or remove it from the Tailnet +2. revoke relevant authentication material +3. review tags, groups and grants +4. remove dedicated SSH authorization where applicable +5. revalidate the remaining approved path +6. record only an anonymized outcome publicly ## Documentation rule -All configuration examples in this repository must be anonymized and non-functional by design. +Every public example must be synthetic or anonymized, clearly labelled and independently reviewed before publication. The repository validator is a guardrail, not a substitute for manual review. \ No newline at end of file diff --git a/docs/setup-notes.md b/docs/setup-notes.md index 76f1b10..ae39f0a 100644 --- a/docs/setup-notes.md +++ b/docs/setup-notes.md @@ -2,79 +2,118 @@ ## Status -The initial managed remote access baseline has been completed. +The initial managed remote-access baseline was completed and last validated in **June 2026**. -Tailscale was installed and tested on all initially intended devices: +The recorded test period included: -- macOS workstation -- Windows school desktop / BBQ OptiPlex Tower -- Windows ThinkPad X1 -- iPhone 12 Pro Max +- personal macOS workstation +- institution-managed Windows desktop +- institution-managed Windows notebook +- personal mobile validation device -All devices were enrolled in the same Tailnet and were able to see and communicate with each other. +The devices were enrolled in the same Tailnet during the test period. Tailnet visibility and selected reachability paths were verified. This does not claim unrestricted communication between every device pair or permanent enrollment. -## Phase 1: Managed remote access test +## Preconditions -Completed tasks: +Before adding a device: -- installed Tailscale on the macOS workstation -- installed Tailscale on the Windows school desktop -- installed Tailscale on the Windows ThinkPad -- installed Tailscale on the iPhone -- verified Tailnet visibility -- tested reachability between devices -- enabled macOS Remote Login for SSH -- tested SSH from the Windows ThinkPad to the macOS workstation over Tailscale -- kept all real Tailscale IP addresses and SSH fingerprints out of Git +1. confirm ownership or organizational permission +2. define the device role and required destination +3. decide whether explicit device approval is required +4. confirm the expected key-expiry behavior +5. ensure no real device identifier will be published +6. define the offboarding trigger -## SSH test +Institution-managed devices must not be enrolled merely because installation is technically possible. -The first practical remote access use case was: +## Recorded baseline steps + +The initial practical workflow was: + +1. install Tailscale on the authorized devices +2. authenticate them to the intended private Tailnet +3. verify device visibility +4. verify selected Tailscale reachability +5. enable native macOS Remote Login for the approved access scope +6. test SSH from the Windows mobile client to the macOS target +7. confirm that no public router port forwarding was used +8. record only anonymized results + +## Recorded SSH path ```text -Windows ThinkPad X1 +WINDOWS_MOBILE_CLIENT | - | SSH over Tailscale - | -macOS workstation at home + | native SSH / TCP 22 + | transported over Tailscale + v +MACOS_REMOTE_TARGET ``` -The SSH test succeeded. +The test succeeded during the recorded validation period. -The first SSH host key prompt was accepted after verifying the intended Tailscale hostname. +The public repository does not disclose: -No public router port forwarding was used. +- the real source or target hostname +- the local user name +- the Tailnet name +- addresses +- keys +- fingerprints +- the exact private authentication configuration -## Features intentionally not enabled +## Features outside the baseline -The following Tailscale features were intentionally not enabled during the initial setup: +The initial setup did not enable: - Exit Node - Subnet Router - Funnel - Serve - Tailscale SSH +- public WireGuard server operation +- public router port forwarding + +## Access-control follow-up + +The public repository now documents a least-privilege target model. The exact private Tailnet policy is not published and must be reviewed separately. + +The intended path permits only the required managed-client-to-macOS-target service. General client-to-client or unrelated-device access is not required. + +See [Access-control model](access-control-model.md). + +## Device lifecycle + +For each enrolled device, review periodically: + +- continued authorization +- continued business or learning need +- client version +- key-expiry state +- device approval state +- current management status +- offboarding readiness + +Remove or disable a device when it is returned, reassigned, lost, compromised, no longer authorized or no longer required. -The current setup uses Tailscale only as a private connectivity layer between trusted devices. +## WireGuard learning phase -## Phase 2: WireGuard learning lab +WireGuard remains a separate learning exercise. Any future implementation should: -Planned tasks: +- use a dedicated lab boundary rather than the productive workstation where practical +- keep all private keys outside Git +- document peers and `AllowedIPs` +- distinguish split-tunnel and full-tunnel behavior +- document routing and firewall assumptions +- avoid public service exposure without a separate risk review -- create WireGuard key pairs -- define peers -- document AllowedIPs -- test split tunnel behavior -- document routing assumptions -- document troubleshooting steps -- keep all secrets out of Git +## Publication checklist -## Test checklist +Before publishing setup changes: -- VPN client starts successfully -- target device is reachable by Tailscale name -- local network services are not exposed publicly -- SSH works over Tailscale -- real Tailscale IP addresses are not committed -- SSH fingerprints are not committed -- no sensitive values are committed to Git +- replace real names with role names +- remove exact addresses and fingerprints +- remove organization-specific device identifiers +- verify that planned work is not described as implemented +- run `python scripts/validate_public_repository.py` +- review the final diff manually diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 0a9abe9..22b9cbc 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,89 +1,140 @@ # Troubleshooting -## Device not reachable +Troubleshooting should distinguish connectivity, service availability, authorization and device-lifecycle problems. Output must be anonymized before publication. -Check: +## Device not visible or reachable + +Check privately: + +- the device is powered on and connected +- the Tailscale client is running +- the device is authenticated to the expected Tailnet +- the device is approved if approval is required +- the device key has not expired +- the device is still authorized and needed +- the correct private device name is being used +- the access policy permits the intended source, destination and service -- VPN client is running on both devices -- device is online -- device is logged into the expected Tailnet -- correct Tailscale device name is used -- local firewall allows the intended service -- target service is actually enabled +Do not publish the real device name, Tailnet name or address while documenting the result. -## SSH does not connect +## Tailscale visibility works but the service does not + +Tailnet visibility does not prove that a particular service is reachable. Check: -- Remote Login is enabled on the macOS target -- SSH server is listening on port 22 -- Tailscale connection is active -- correct Tailscale hostname is used -- correct macOS user name is used -- the user is allowed to use Remote Login -- firewall does not block SSH +- the destination service is running +- the service is listening on the expected interface and port +- the local firewall permits the traffic +- the private Tailnet policy permits the path +- the source device is in the intended role +- the destination device is available -On macOS, Remote Login can be checked with: +## Native SSH does not connect -```text -sudo systemsetup -getremotelogin -``` +For the documented macOS target, check privately: + +- Remote Login is enabled +- the intended local account is authorized +- the SSH service is listening on TCP 22 +- Tailscale is connected on both endpoints +- the access policy permits TCP 22 from the client role to the target role +- the authentication method is still valid +- no stale host-key or account assumption is being used -SSH listening state can be checked with: +macOS checks: ```text +sudo systemsetup -getremotelogin sudo lsof -iTCP:22 -sTCP:LISTEN -n -P ``` -## Tailscale ping works only via DERP relay +Sanitize command output before publication. Do not publish login names, fingerprints, keys or full SSH configuration. + +## Access policy denies a valid use case -This is not automatically a failure. +Review: -A DERP relay path means Tailscale could not establish a direct peer-to-peer connection and used a relay instead. +- source role or tag +- destination role or tag +- required protocol and port +- whether the device was approved +- whether the rule is intentionally absent +- whether the requested access expands the documented scope -Possible reasons: +Do not solve a narrow policy issue by granting broad client-to-client or all-port access without a separate review. + +## Tailscale ping uses DERP + +A DERP relay path is not automatically a failure. It indicates that a direct peer-to-peer path was not established for that test. + +Possible causes include: - restrictive NAT -- firewall rules -- school or enterprise network restrictions -- UDP restrictions +- firewall or UDP restrictions +- school or enterprise network policy - temporary network conditions -For the initial lab state, reachability through DERP is acceptable. +Record the observed path with a validation date. Do not describe it as a permanent property of the architecture. + +## Institution-managed device appears offline + +Possible causes include: -## Windows school desktop appears offline +- sleep or power management +- school-network restrictions +- Tailscale service state +- reassignment or endpoint-management changes +- expired authorization or device key +- device return or decommissioning -Possible reasons: +Before restoring access, confirm that continued enrollment remains permitted and necessary. -- Windows is sleeping -- network adapter power saving is active -- school network disconnected idle clients -- Tailscale service is not active -- user session was locked and background connectivity changed +## Device should no longer have access -This is acceptable for the current lab if the primary use case is ThinkPad to macOS workstation. +Treat return, loss, compromise, reassignment or loss of authorization as an offboarding event: + +1. disable or remove the device from the Tailnet +2. revoke relevant authentication material +3. review groups, tags and grants +4. remove dedicated SSH authorization where applicable +5. revalidate the remaining approved path +6. publish only an anonymized outcome ## VPN connects but no traffic flows Check: -- Tailnet device status -- route configuration -- local firewall rules +- device approval and key status +- policy grants +- local firewall - service-specific permissions - name resolution -- split tunnel assumptions +- route assumptions +- whether subnet or exit-node routing was incorrectly assumed + +The current baseline does not enable subnet routing or an exit node. -## macOS target wakes or sleeps unexpectedly +## macOS target is unavailable Check: -- Energy Saver settings -- wake for network access -- external SSD sleep behavior +- power and sleep state +- active network connectivity +- required user-session state +- Tailscale client state - Remote Login state -- whether the iMac is expected to stay reachable continuously +- local firewall + +The iMac is a personal productive endpoint, not an always-available server. ## Documentation rule -Any troubleshooting output added to this repository must be anonymized before publishing. +Before adding troubleshooting evidence: + +- replace real hostnames with public role names +- remove addresses, account names and fingerprints +- avoid raw admin-console screenshots +- state the validation date +- distinguish observed facts from hypotheses +- run `python scripts/validate_public_repository.py` diff --git a/docs/validation-checklist.md b/docs/validation-checklist.md index 814b8a5..91e7c1d 100644 --- a/docs/validation-checklist.md +++ b/docs/validation-checklist.md @@ -1,62 +1,118 @@ # Validation checklist -This checklist is used to keep the lab documentation consistent, safe and reproducible without publishing sensitive infrastructure details. +Use this checklist before publishing changes or revalidating the lab. + +## Repository safety + +Verify that the repository does not contain: + +- [ ] private keys, auth keys or authentication tokens +- [ ] device enrollment links or QR codes +- [ ] real public, private or Tailscale IP addresses +- [ ] real hostnames, Tailnet names or account identities +- [ ] real SSH fingerprints or authorized-key material +- [ ] private Tailnet policy exports +- [ ] organization-specific asset or management identifiers +- [ ] screenshots with private account, device or infrastructure data +- [ ] complete internal topology +- [ ] raw command output that has not been reviewed and sanitized + +## Documentation consistency + +Verify that: + +- [ ] README and detailed documents describe the same current state +- [ ] recorded tests include a validation date +- [ ] device visibility is not described as unrestricted service access +- [ ] selected tests are not generalized to every device pair +- [ ] the macOS workstation is not described as having an availability commitment +- [ ] institution-managed devices are described as temporary and authorization-dependent +- [ ] planned controls are not described as already implemented +- [ ] the exact private access policy is not published +- [ ] every example is clearly synthetic or anonymized + +## Device authorization and lifecycle + +For each enrolled device, verify privately: + +- [ ] ownership or organizational permission is still valid +- [ ] the device is still needed for the documented use case +- [ ] the device is approved if approval is required +- [ ] key-expiry behavior is known and appropriate +- [ ] the Tailscale client is current +- [ ] management status has not changed unexpectedly +- [ ] return, reassignment, loss or compromise has not triggered offboarding +- [ ] stale devices have been disabled or removed + +## Access-control review + +Verify privately: + +- [ ] the source role is authorized +- [ ] the destination role is correct +- [ ] only the required service and port are permitted +- [ ] general client-to-client access is not assumed +- [ ] unrelated personal devices are not included by accident +- [ ] mobile validation does not imply SSH permission +- [ ] subnet routes and exit-node routes remain outside the baseline +- [ ] Funnel, Serve and Tailscale SSH remain disabled unless separately reviewed + +## Native SSH validation + +For the documented path, verify privately: + +- [ ] the macOS target is available +- [ ] Remote Login is enabled only as intended +- [ ] the intended account is authorized +- [ ] TCP 22 is permitted through the private path +- [ ] public router port forwarding remains absent +- [ ] authentication material is current +- [ ] stale client authorization has been removed +- [ ] no user name, key or fingerprint is copied into public evidence + +## Connection-test record + +A public test record should include only: + +- [ ] validation date or month +- [ ] public source role +- [ ] public target role +- [ ] tested service and port +- [ ] pass/fail result +- [ ] direct or relay path if relevant +- [ ] confirmation that public port forwarding was absent +- [ ] a statement of limitations + +## Local repository validation -## Repository safety checks - -Before publishing changes, verify that the repository does not contain: - -- [ ] private keys -- [ ] authentication tokens -- [ ] VPN enrollment links -- [ ] QR codes -- [ ] real public IP addresses -- [ ] real private IP addresses -- [ ] real Tailscale IP addresses -- [ ] real SSH fingerprints -- [ ] real account names where avoidable -- [ ] screenshots with private account or device data -- [ ] complete internal network details - -## Documentation checks - -Before committing documentation updates, verify that: - -- [ ] the README still describes the current lab state accurately -- [ ] architecture notes match the documented device roles -- [ ] connection tests are anonymized -- [ ] security considerations mention features that were intentionally not enabled -- [ ] example configurations are clearly non-functional -- [ ] planned work is not described as already implemented -- [ ] limitations are stated clearly - -## Technical validation checks +Before committing: -For the current Tailscale baseline, validate only with anonymized results: +```bash +python scripts/validate_public_repository.py +git status --short +git diff --check +git diff +``` -- [ ] devices are visible in the Tailnet -- [ ] the intended remote access target is reachable over Tailscale -- [ ] SSH access works only through the private VPN path -- [ ] no public router port forwarding is required -- [ ] no unnecessary Tailscale features are enabled -- [ ] mobile validation is optional and documented separately if used +Verify that: -## Git workflow checks +- [ ] the validation script passes +- [ ] only intended files changed +- [ ] no generated local configuration was added +- [ ] no secret-like value appears in the diff +- [ ] the commit message describes the actual change -Before committing: +## Offboarding -- [ ] run git status -- [ ] review git diff -- [ ] check that no generated secrets or local config files were added -- [ ] use a specific commit message -- [ ] keep the commit small and explainable +When a device is returned, reassigned, lost, compromised or no longer required: -Suggested commit message for this documentation update: - -Add portfolio context and validation checklist +- [ ] disable or remove it from the Tailnet +- [ ] revoke relevant authentication material +- [ ] review tags, groups and grants +- [ ] remove dedicated SSH authorization where applicable +- [ ] revalidate the remaining approved path +- [ ] publish only an anonymized outcome ## Review principle -This project should grow in small, reviewable steps. - -A useful change should make the lab easier to understand, safer to publish or easier to validate. Changes should not add complexity just to make the repository look larger. +A useful change should make the lab safer, clearer or easier to validate. Do not add public exposure, infrastructure products or broad permissions solely to make the repository appear more advanced. diff --git a/examples/tailnet-policy.example.hujson b/examples/tailnet-policy.example.hujson new file mode 100644 index 0000000..2cf9ad4 --- /dev/null +++ b/examples/tailnet-policy.example.hujson @@ -0,0 +1,14 @@ +{ + "tagOwners": { + "tag:remote-target": ["autogroup:admin"], + "tag:managed-client": ["autogroup:admin"], + "tag:mobile-validation": ["autogroup:admin"] + }, + "grants": [ + { + "src": ["tag:managed-client"], + "dst": ["tag:remote-target"], + "ip": ["tcp:22"] + } + ] +} diff --git a/scripts/validate_public_repository.py b/scripts/validate_public_repository.py new file mode 100644 index 0000000..9b6bf99 --- /dev/null +++ b/scripts/validate_public_repository.py @@ -0,0 +1,160 @@ +"""Validate selected public-safety invariants for the repository. + +This is a lightweight guardrail. It does not replace manual review of diffs, +private configuration, screenshots, account data or infrastructure exports. +""" + +from __future__ import annotations + +import json +import re +from pathlib import Path + + +VALIDATOR_PATH = Path(__file__).resolve() +REPOSITORY_ROOT = VALIDATOR_PATH.parents[1] +POLICY_EXAMPLE = REPOSITORY_ROOT / "examples" / "tailnet-policy.example.hujson" + +REQUIRED_PATHS = ( + REPOSITORY_ROOT / "README.md", + REPOSITORY_ROOT / "docs" / "access-control-model.md", + REPOSITORY_ROOT / "docs" / "connection-tests.md", + REPOSITORY_ROOT / "docs" / "security-considerations.md", + REPOSITORY_ROOT / "docs" / "validation-checklist.md", + POLICY_EXAMPLE, +) + +TEXT_SUFFIXES = { + ".conf", + ".hujson", + ".md", + ".py", + ".txt", + ".yaml", + ".yml", +} + +FORBIDDEN_LITERALS = { + "".join(("BBQ-", "BM6HJ64")): "real institution-managed desktop hostname", + "".join(("BBQEDU-", "PF3NRBA0")): "real institution-managed notebook hostname", +} + +FORBIDDEN_PATTERNS = ( + ( + re.compile(r"\b100(?:\.\d{1,3}){3}\b"), + "real-looking Tailscale IPv4 address", + ), + ( + re.compile(r"-----BEGIN (?:OPENSSH |RSA |EC )?PRIVATE KEY-----"), + "private-key material", + ), + ( + re.compile(r"\bSHA256:[A-Za-z0-9+/]{20,}={0,2}\b"), + "SSH fingerprint", + ), + ( + re.compile(r"\btskey-[A-Za-z0-9-]{12,}\b"), + "Tailscale authentication key", + ), +) + + +def iter_public_text_files() -> list[Path]: + """Return public text files that should be checked.""" + files: list[Path] = [] + for path in REPOSITORY_ROOT.rglob("*"): + if not path.is_file() or ".git" in path.parts: + continue + if path.resolve() == VALIDATOR_PATH: + continue + if path.name == ".gitignore" or path.suffix.lower() in TEXT_SUFFIXES: + files.append(path) + return sorted(files) + + +def validate_required_paths(errors: list[str]) -> None: + for path in REQUIRED_PATHS: + if not path.is_file(): + relative = path.relative_to(REPOSITORY_ROOT) + errors.append(f"Missing required public-safety artifact: {relative}") + + +def validate_text_files(errors: list[str]) -> None: + for path in iter_public_text_files(): + relative = path.relative_to(REPOSITORY_ROOT) + text = path.read_text(encoding="utf-8") + + for literal, description in FORBIDDEN_LITERALS.items(): + if literal in text: + errors.append(f"{relative}: contains {description}") + + for pattern, description in FORBIDDEN_PATTERNS: + if pattern.search(text): + errors.append(f"{relative}: contains {description}") + + if path.suffix.lower() == ".conf": + for line_number, line in enumerate(text.splitlines(), start=1): + stripped = line.strip() + if not stripped.startswith("PrivateKey") or "=" not in stripped: + continue + value = stripped.split("=", maxsplit=1)[1].strip() + if not (value.startswith("<") and value.endswith(">")): + errors.append( + f"{relative}:{line_number}: contains a non-placeholder PrivateKey value" + ) + + +def validate_policy_example(errors: list[str]) -> None: + if not POLICY_EXAMPLE.is_file(): + return + + try: + policy = json.loads(POLICY_EXAMPLE.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + errors.append(f"Policy example is not valid JSON-compatible HUJSON: {exc}") + return + + grants = policy.get("grants") + if not isinstance(grants, list) or len(grants) != 1: + errors.append("Policy example must contain exactly one narrow grant") + return + + expected_grant = { + "src": ["tag:managed-client"], + "dst": ["tag:remote-target"], + "ip": ["tcp:22"], + } + if grants[0] != expected_grant: + errors.append( + "Policy example must grant only managed-client -> remote-target on tcp:22" + ) + + serialized = json.dumps(policy, sort_keys=True) + for value in ("autogroup:internet", "0.0.0.0/0", "::/0", "*:*"): + if value in serialized: + errors.append( + "Policy example contains an over-broad destination or capability: " + f"{value}" + ) + + +def main() -> int: + errors: list[str] = [] + validate_required_paths(errors) + validate_text_files(errors) + validate_policy_example(errors) + + if errors: + print("Public repository validation failed:") + for error in errors: + print(f"- {error}") + return 1 + + print("Public repository validation passed.") + print(f"Checked text files: {len(iter_public_text_files())}") + print("Policy scope: tag:managed-client -> tag:remote-target on tcp:22") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())