Skip to content

Commit

Permalink
Merge pull request #65 from sevensolutions/feature/website
Browse files Browse the repository at this point in the history
Feature/website
  • Loading branch information
sevensolutions authored Aug 22, 2024
2 parents 7ee42ef + c215c6b commit 5bc8aca
Show file tree
Hide file tree
Showing 18 changed files with 321 additions and 281 deletions.
240 changes: 2 additions & 238 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,245 +36,9 @@ Feel free to use it as-is or as a reference implementation for your own C#-based
| Filesystem Isolation | 🔶 | [Details](#-filesystem-isolation) |
| Nomad Networking || |

## 🖥 Client Requirements
## 📚 Documentation

- Windows Server 2016+
- Microsoft IIS 10.0+

## ⚙ Driver Configuration

| Option | Type | Required | Default Value | Description |
|---|---|---|---|---|
| enabled | bool | no | true | Enables/Disables the Nomad IIS Plugin |
| fingerprint_interval | string | no | 30s | Defines the interval how often the plugin should report the driver's fingerprint to Nomad. The smallest possible value is 10s. |
| directory_security | bool | no | true | Enables Directory Permission Management for [Filesystem Isolation](#-filesystem-isolation). |
| allowed_target_websites | string[] | no | *none* | A list of IIS websites which are allowed to be used as [target_website](#-using-an-existing-website). An asterisk (*\**) may be used as a wildcard to allow any website. |
| udp_logger_port | number | no | 64001 | The local UDP port where the driver is listening for log-events which will be shipped to the Nomad client. The value 0 will disable this feature. Please read the details [here](#-udp-logging). |

**Example**

```hcl
plugin "nomad_iis" {
#args = ["--port 1234"] # Optional. To change the static port. The default is 5003.
#args = ["--port 0"] # Optional. To use a random port
config {
enabled = true,
fingerprint_interval = "30s",
directory_security = true
allowed_target_websites = [ "Default Web Site" ]
}
}
```

## ⚙ Task Configuration

| Option | Type | Required | Default Value | Description |
|---|---|---|---|---|
| *application* | block list | yes | *none* | Defines one more applications. See *application* schema below for details. |
| target_website | string | no | *none* | Specifies an existing target website. In this case the driver will not create a new website but instead use the existing one where it provisions the virtual applications only. Please read the details [here]([Details](#-using-an-existing-website)). |
| managed_pipeline_mode | string | no | *IIS default* | Valid options are *Integrated* or *Classic* |
| managed_runtime_version | string | no | *IIS default* | Valid options are *v4.0*, *v2.0*, *None* |
| start_mode | string | no | *IIS default* | Valid options are *OnDemand* or *AlwaysRunning* |
| idle_timeout | string | no | *IIS default* | The AppPool idle timeout in the form *HH:mm:ss* or *[00w][00d][00h][00m][00s]* |
| disable_overlapped_recycle | bool | no | *IIS default* | Defines whether two AppPools are allowed to run while recycling |
| periodic_restart | string | no | *IIS default* | The AppPool periodic restart interval in the form *HH:mm:ss* or *[00w][00d][00h][00m][00s]* |
| enable_udp_logging | bool | no | false | Enables a UDP log-sink your application can log to. Please read the details [here](#-udp-logging). |
| permit_iusr | bool | no | true | Specifies whether you want to permit the [IUSR-account](https://learn.microsoft.com/en-us/iis/get-started/planning-for-security/understanding-built-in-user-and-group-accounts-in-iis#understanding-the-new-iusr-account) on the *local* directory. When you disable this, you may need to tweak your *web.config* a bit. Read [this](#anonymous-authentication-and-the-iusr-account) for details. |
| *binding* | block list | yes | *none* | Defines one or two port bindings. See *binding* schema below for details. |

### `application` Block Configuration

| Option | Type | Required | Default Value | Description |
|---|---|---|---|---|
| path | string | yes | *none* | Defines the path of the web application, containing the application files |
| alias | string | no | / | Defines an optional alias at which the application should be hosted below the website. If not set, the application will be hosted at the website level. |
| enable_preload | bool | no | *IIS default* | Specifies whether the application should be pre-loaded. |
| *virtual_directory* | block list | no | *none* | Defines optional virtual directories below this application. See *virtual_directory* schema below for details. |

### `virtual_directory` Block Configuration

| Option | Type | Required | Default Value | Description |
|---|---|---|---|---|
| alias | string | yes | *none* | Defines the alias of the virtual directory |
| path | string | yes | *none* | Defines the path of the virtual directory |

### `binding` Block Configuration

| Option | Type | Required | Default Value | Description |
|---|---|---|---|---|
| type | string | yes | *none* | Defines the protocol of the port binding. Allowed values are *http* or *https*. |
| port | string | yes | *none* | Defines the port label of a `network` block configuration or a static port like "80". Static ports can only be used when *hostname* is also set. Otherwise use a nomad *network*-stanza to specify the port. |
| hostname | string | no | *IIS default* | Only listens to the specified hostname |
| require_sni | bool | no | *IIS default* | Defines whether SNI (Server Name Indication) is required |
| ip_address | string | no | *IIS default* | Specifies the IP-Address of the interface to listen on |
| certificate_hash | string | no | *none* | Specifies the hash of the certificate to use when using type=https |

**Example**

**Note:** The following example downloads a very simple HTML app from this repository.
Feel free to inspect the ZIP before running the job.

```hcl
job "static-sample-app" {
datacenters = ["dc1"]
type = "service"
group "app" {
count = 1
# You may want to set this to true
# prevent_reschedule_on_lost = true
network {
port "httplabel" {}
}
task "app" {
driver = "iis"
artifact {
source = "https://github.com/sevensolutions/nomad-iis/raw/main/examples/static-sample-app.zip"
destination = "local"
}
config {
application {
path = "local"
}
binding {
type = "http"
port = "httplabel"
}
}
resources {
cpu = 100
memory = 20
}
}
}
}
```

## 🌎 Environment Variables

All System Environment Variables available to the Nomad Client will be applied to the Application Pool.
You can supply additional ones by using the [`env` Block](https://developer.hashicorp.com/nomad/docs/job-specification/env) in the `task` stanza.

## ✨ Supported Signals

The Nomad IIS driver supports the following signals:

| Signal | Description |
|---|---|
| `SIGHUP` or `RECYCLE` | Recycles the Application Pool |
| `SIGINT` or `SIGKILL` | Stops and removes the Application. Note: When sending this signal manually, the job gets re-scheduled. |

To send a *RECYCLE* signal, run:

```
nomad alloc signal -s RECYCLE <allocation> <task>
```

Details about the command can be found [here](https://developer.hashicorp.com/nomad/docs/commands/alloc/signal).

## 🛡 Filesystem Isolation

Because there is no `chroot` on Windows, filesystem isolation is only handled via permissions.
For every AppPool, IIS creates a dedicated AppPool Service Account which is only allowed to access it's own directories. See commits of [GH-5](https://github.com/sevensolutions/nomad-iis/issues/5) for details.

Given a job spec with two tasks, the following table depicts the permissions for each AppPool *task1* and *task2* inside the [allocation directory](https://developer.hashicorp.com/nomad/docs/concepts/filesystem).

| Directory | Access Level |
|---|---|
| `/alloc` | No Access |
| `/alloc/data` | Full Access for *task1* and *task2* |
| `/alloc/logs` | Full Access for *task1* and *task2* |
| `/alloc/tmp` | Full Access for *task1* and *task2* |
| `/task1/local` | Full Access for *task1* |
| `/task1/private` | No Access |
| `/task1/secrets` | Read Only for *task1*, No Access for *task2*, no file listing |
| `/task1/tmp` | Full Access for *task1* |
| `/task2/local` | Full Access for *task2* |
| `/task2/private` | No Access |
| `/task2/secrets` | Read Only for *task2*, No Access for *task1*, no file listing |
| `/task2/tmp` | Full Access for *task2* |

## 🌐 Using an existing Website

By specifying a *target_website* in the task configuration you can re-use an existing website managed outside of nomad.
In this case the driver will not create a new website but instead use the existing one where it provisions the virtual applications only.

Note that there're a few restrictions when using a target_website:

- The feature [needs to be enabled](#-driver-configuration).
- Re-using an existing website managed by nomad (owned by a different job or task), is not allowed.
- Bindings and other website-related configuration will have no effect.
- You need to make sure you constrain your jobs to nodes having this target_website available, otherwise the job will fail.
- You cannot create a root-application when using a target_website.

## 💬 UDP Logging

> [!WARNING]
> This feature is considered experimental and not very well tested yet.
Unfortunately, IIS doesn't attach a Console to the *w3wp* processes and therefore *STDOUT* and *STDERR* streams are not available.
As a solution, *nomad-iis* can provide a UDP-endpoint and ship those log messages to the Nomad-Client.

The UDP log-sink exposes two more environment variables:

| Name | Description |
|---|---|
| `NOMAD_STDOUT_UDP_LOCAL_PORT` | The local port the appender has to use. Only messages from this port get received and forwarded to nomad. |
| `NOMAD_STDOUT_UDP_REMOTE_PORT` | The remote port of the log-sink where log events must be sent to. |

Please note, that you need to configure your app's logging provider to log to this UDP endpoint.
Here is an example log4net-appender on how to log to the UDP log-sink:

```xml
<appender name="UdpAppender" type="log4net.Appender.UdpAppender">
<localPort value="${NOMAD_STDOUT_UDP_LOCAL_PORT}" />
<remoteAddress value="127.0.0.1" />
<remotePort value="${NOMAD_STDOUT_UDP_REMOTE_PORT}" />
<layout type="log4net.Layout.PatternLayout, log4net">
<conversionPattern value="%d{dd.MM.yy HH:mm:ss.fff} %-5p [%-8t] %-35logger - %m%newline" />
</layout>
</appender>
```

## 💡 Good to know / FAQ

### Anonymous Authentication and the IUSR account

By default, this driver will permit the built-in [*IUSR-account*](https://learn.microsoft.com/en-us/iis/get-started/planning-for-security/understanding-built-in-user-and-group-accounts-in-iis#understanding-the-new-iusr-account) to the *local* task directory.
This should allow anonymous authentication to work directly.
You can optionally disable this by setting `permit_iusr = false`.
In this case you may need to add the following snippet to your *web.config* to make anonymous authentication use the *AppPoolIdentity* instead.

```xml
<configuration>
<system.webServer>
<security>
<authentication>
<anonymousAuthentication userName="" />
</authentication>
</security>
</system.webServer>
</configuration>
```

> [!IMPORTANT]
> By default, changing the anonymous authentication via custom web.config is not allowed in IIS and you will get a *500 - Internal Server Error*.
> The corresponding section is locked on IIS Instance level.
> To unlock it, open the IIS Management Console, select the Server node on the left side and then navigate to *Feature Delegation*. Look for the entry *Authentication - Anonymous* and change it to *Read/Write*.
> If you want to automate this process, run the following Powershell Command:
> `Set-WebConfiguration //System.WebServer/Security/Authentication/anonymousAuthentication -metadata overrideMode -value Allow -PSPath IIS:/`
### asp-net-sample-app returns 500 - Internal Server Error

The asp-net-sample-app changes the anonymous authentication in a way, so that the App Pool Identity is being used.
Please see the *Important*-box above.
Please see the full documentation [HERE](https://nomad-iis.sevensolutions.cc/).

## 🛠 How to Compile

Expand Down
22 changes: 3 additions & 19 deletions website/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,21 @@ This website is built using [Docusaurus](https://docusaurus.io/), a modern stati
### Installation

```
$ yarn
$ npm i
```

### Local Development

```
$ yarn start
$ npm start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

### Build

```
$ yarn build
$ npm run build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

### Deployment

Using SSH:

```
$ USE_SSH=true yarn deploy
```

Not using SSH:

```
$ GIT_USER=<Your GitHub username> yarn deploy
```

If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
4 changes: 4 additions & 0 deletions website/docs/features/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Features",
"position": 1
}
8 changes: 8 additions & 0 deletions website/docs/features/environment-variables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
sidebar_position: 2
---

# 🌎 Environment Variables

All System Environment Variables, available to the Nomad Client, will be applied to the Application Pool.
You can supply additional ones by using the [`env` Block](https://developer.hashicorp.com/nomad/docs/job-specification/env) in the `task` stanza.
16 changes: 16 additions & 0 deletions website/docs/features/existing-website.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
sidebar_position: 5
---

# 🌐 Using an existing Website

By specifying a *target_website* in the task configuration you can re-use an existing website managed outside of nomad.
In this case the driver will not create a new website but instead use the existing one where it provisions the virtual applications only.

Note that there're a few restrictions when using a target_website:

- The feature [needs to be enabled](../getting-started/driver-configuration.md).
- Re-using an existing website managed by nomad (owned by a different job or task), is not allowed.
- Bindings and other website-related configuration will have no effect.
- You need to make sure you constrain your jobs to nodes having this target_website available, otherwise the job will fail.
- You cannot create a root-application when using a target_website.
25 changes: 25 additions & 0 deletions website/docs/features/filesystem-isolation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
sidebar_position: 4
---

# 🛡 Filesystem Isolation

Because there is no `chroot` on Windows, filesystem isolation is only handled via permissions.
For every AppPool, IIS creates a dedicated AppPool Service Account which is only allowed to access it's own directories. See commits of [GH-5](https://github.com/sevensolutions/nomad-iis/issues/5) for details.

Given a job spec with two tasks, the following table depicts the permissions for each AppPool *task1* and *task2* inside the [allocation directory](https://developer.hashicorp.com/nomad/docs/concepts/filesystem).

| Directory | Access Level |
|---|---|
| `/alloc` | No Access |
| `/alloc/data` | Full Access for *task1* and *task2* |
| `/alloc/logs` | Full Access for *task1* and *task2* |
| `/alloc/tmp` | Full Access for *task1* and *task2* |
| `/task1/local` | Full Access for *task1* |
| `/task1/private` | No Access |
| `/task1/secrets` | Read Only for *task1*, No Access for *task2*, no file listing |
| `/task1/tmp` | Full Access for *task1* |
| `/task2/local` | Full Access for *task2* |
| `/task2/private` | No Access |
| `/task2/secrets` | Read Only for *task2*, No Access for *task1*, no file listing |
| `/task2/tmp` | Full Access for *task2* |
7 changes: 7 additions & 0 deletions website/docs/features/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
sidebar_position: 1
---

# Features

This section contains detailed information about all the features supported by *Nomad IIS*.
20 changes: 20 additions & 0 deletions website/docs/features/signals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
sidebar_position: 3
---

# ✨ Signals

The Nomad IIS driver supports the following signals:

| Signal | Description |
|---|---|
| `SIGHUP` or `RECYCLE` | Recycles the Application Pool |
| `SIGINT` or `SIGKILL` | Stops and removes the Application. Note: When sending this signal manually, the job gets re-scheduled. |

To send a *RECYCLE* signal, run:

```
nomad alloc signal -s RECYCLE <allocation> <task>
```

Details about the command can be found [here](https://developer.hashicorp.com/nomad/docs/commands/alloc/signal).
Loading

0 comments on commit 5bc8aca

Please sign in to comment.