Git Product home page Git Product logo

nomad-iis's Introduction

HashiCorp Nomad IIS Task Driver

Build Release License

Nomad IIS Logo

This repository contains a task driver for HashiCorp Nomad to run web-applications in IIS on Windows machines. Unlike most other Nomad task drivers, this one is written in the C# language using ASP.NET 8. It uses the Microsoft.Web.Administration-API to communicate with IIS. Feel free to use it as-is or as a reference implementation for your own C#-based Nomad-plugins.

๐ŸŽ‰ Features

Feature Status Details
Single Web App per Nomad Task โœ” The Task Driver creates an IIS Application Pool and Website for every Nomad Task in the job specification.
Multiple Applications โœ” Support for multiple sub-applications below the website.
Virtual Directories โœ” Support for multiple virtual directories below an application.
HTTP Bindings โœ”
HTTPS Bindings โœ” GH-3
Environment Variables โœ” Details
Resource Statistics โœ”
Logging โœ” Experimental UDP logging. See GH-6 for details.
Signals with nomad alloc signal โœ” Details
Exec (Shell Access) โŒ I'am playing around a little bit but don't want to give you hope :/. See GH-15 for status.
Filesystem Isolation ๐Ÿ”ถ Details
Nomad Networking โŒ

๐Ÿ–ฅ Client Requirements

  • 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.
allowed_target_websites string[] no none A list of IIS websites which are allowed to be used as target_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.

Example

plugin "nomad_iis" {
  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.
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.
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

job "iis-test" {
  datacenters = ["dc1"]
  type = "service"

  group "iis-test" {
    count = 1

    # You may want to set this to true
    # prevent_reschedule_on_lost = true
	
    network {
      port "httplabel" {}
    }

    task "iis-test" {
      driver = "iis"

      config {
        application {
          path = "C:\\inetpub\\wwwroot"
        }
		
        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 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.

๐Ÿ›ก 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 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.

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.
  • 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

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:

<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>

๐Ÿ›  How to Compile

Run the setup command to download the nomad binary.

.\setup.ps1

Build the project by running the following command:

cd src
dotnet build

Of course you can also compile with Visual Studio :)

๐Ÿ› How to Debug locally

There is a launch-profile to run nomad in dev-mode which automatically loads the driver plugin. Open Visual Studio, select the Nomad launch profile and press F5.

Note: To debug the driver itself, you need to attach the debugger to the nomad_iis.exe process manually.

๐ŸŽ How to build Release version

Run the Release.pubxml publish profile from Visual Studio. This will create a single binary exe called nomad_iis.exe.

๐Ÿšง TODOs and Known Issues

Check the Open Issues here.

โ˜• Support

You want to support me?

Buy Me A Coffee

nomad-iis's People

Contributors

dependabot[bot] avatar sevensolutions avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

nomad-iis's Issues

Wrong ACL permissions

It looks like ACL permissions are still wrong. They are propagating to "Subfolders and files only" but should be "This folder, subfolders and files".

Possible "out of IDs" for websites

Websites in IIS need a unique numeric id. Currently, we're using max+1 as the next id.
Therefore you may run out of ids some time.
We should use the smallest available id.

Implement Exec

Try to implement the exec functionality if it is possible to do that under the AppPool identity.

IIS Task uses wrong path

At the moment the website path is relative to the allocation directory but when using an artifact block, content is being put into the task-directory.
Maybe we should make the website path relative to the task-directory?

NoManagedRuntime not possible

At the moment we cannot specify "NoManagedRuntime" for the RuntimeVersion.
This is needed when hosting ASP.NET Core Applications inside IIS.

Logging Support

IIS worker processes don't log to stdout which is pretty bad.
But maybe we can provide a named pipe to the application so the app developer can configure logging to it manually.

Nomad is already creating a named pipe for logging, but only the Administrator account is permitted to access it.
So we should try to wrap it into a new one and permit the AppPool user.

Filesize Limits

Allow to specify file size limits on the alloc directory and maybe stop the app on an overusage.

Remove hardcoded port

Remove the hardcoded HTTP port 5003 from Program.cs.
It should be dynamic and already gets exposed by the HandshakeService.

First Website doesnt start

If i have an empty IIS with no existing website and schedule the first one via Nomad, it doesn't start throwing a HTTP 500.
The problem is that we start at an Id 0 instead of 1 when numbering websites. A 0 doesn't get written to the applicationHost.config which seems to corrupt it.

Management API

Implement an optional management API for administrative tasks. The API could be called by a higher order management service, sitting on top of nomad.

Examples would be:

  • Creating a memory dump of a w3wp process
  • Download some internal IIS logs
  • Clean up orphan websites if any #14
  • Allow patching of files in a running website
  • etc

Normalize Paths

The web app fails to load the web.config, if someone specifies a path using a slash (Linux stlye) instead of a backslash.

Eg.

application {
   path = "local/app"
}

We should normalize all paths.

Clean up orphaned Websites

Although it is very unlikely, but it may happen, that sometimes an AppPool and/or website is not getting removed.
We should implement a task for finding and destroying them periodically.
This should be a driver-option with default = false.

Application Only Mode

Currently, deploying an IIS job will always create a new website and application.
I need a way to deploy a new application into an existing website which is managed outside of nomad.
This is needed especially in situations where you have an existing server where you only want to manage "some" applications by nomad.

I'am thinking about something like:

config {
  target_website = "Default Web Site"

  application {
    path = "..."
  }
}

This will only manage the application inside the specified website but never touch the website itself.

There're a few restrictions:

  • Defining bindings or other website-related settings must be prohibited
  • All applications need to use an alias and they must be unique on the target node
    • It would be a good idea to define some client-metadata to ensure jobs are only scheduled on the right nodes containing the website
  • There can be no nomad-managed root-application because changing it's path would require to re-create it

Update to .NET 8

Update to .NET 8 because it's LTS.
Update all dependencies.
Dont forget to update the readme.

Load User Profile

Add support for loading the user profile of an AppPool.
Because this creates a new directory in C:\Users, we also need to clean this up when purging the job.

Custom API Signals

It would be a cool idea to allow to define some REST-API calls which can then be invoked by a signal.
Something like:

signal {
  name = "SIGUSR1"
  path = "/api/signals/sigusr1"
  method = "GET"
  headers = {
    X-Api-Key = "Some API Key"
  }
}

May be usefull to execute some management tasks.
The API may listen to localhost only.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.