Skip to content

Enterprise Testing System #463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions eng/pipelines/libraries/enterprise/linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

# Disable pipeline for ordinary pushes to the branches
trigger: none

# To reduce load on the pipeline, enable it only for PRs that affect critical networking code
pr:
branches:
include:
- master
- release/*.*

paths:
include:
- src/libraries/Common/src/System/Net/*
- src/libraries/Common/tests/System/Net/*
- src/libraries/Native/Unix/System.Net.Security.Native/*
- src/libraries/System.Net.Http/*
- src/libraries/System.Net.Security/*

pool:
vmImage: 'ubuntu-16.04'

variables:
- template: ../variables.yml
- name: enterpriseTestsSetup
value: $(sourcesRoot)/Common/tests/System/Net/EnterpriseTests/setup
- name: containerRunTestsCommand
value: /repo/.dotnet/dotnet msbuild /t:rebuildandtest
- name: containerLibrariesRoot
value: /repo/src/libraries

steps:
- bash: |
cd $(enterpriseTestsSetup)
docker-compose build
displayName: Build test machine images
env:
DOTNET_RUNTIME_REPO_ROOT: $(Build.SourcesDirectory)

- bash: |
cd $(enterpriseTestsSetup)
docker-compose up -d
displayName: Start test network and machines
env:
DOTNET_RUNTIME_REPO_ROOT: $(Build.SourcesDirectory)

- bash: |
docker exec linuxclient bash /setup/test-webserver.sh
displayName: Test linuxclient connection to web server

- bash: |
docker exec linuxclient bash /repo/libraries.sh
displayName: Build product sources

- bash: |
docker exec linuxclient $(containerRunTestsCommand) $(containerLibrariesRoot)/System.Net.Http/tests/EnterpriseTests/System.Net.Http.Enterprise.Tests.csproj
docker exec linuxclient $(containerRunTestsCommand) $(containerLibrariesRoot)/System.Net.Security/tests/EnterpriseTests/System.Net.Security.Enterprise.Tests.csproj
displayName: Build and run tests

- bash: |
cd $(enterpriseTestsSetup)
docker-compose down
displayName: Stop test network and machines
env:
DOTNET_RUNTIME_REPO_ROOT: $(Build.SourcesDirectory)

- task: PublishTestResults@2
inputs:
testRunner: 'xUnit'
testResultsFiles: '**/testResults.xml'
testRunTitle: 'Enterprise Tests'
mergeTestResults: true
failTaskOnFailedTests: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Net.Test.Common
{
public static class EnterpriseTestConfiguration
{
public const string Realm = "LINUX.CONTOSO.COM";
public const string NegotiateAuthWebServer = "http://apacheweb.linux.contoso.com";

public static bool Enabled => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DOTNET_RUNTIME_ENTERPRISETESTS_ENABLED"));
public static NetworkCredential ValidNetworkCredentials => new NetworkCredential("user1", "password");
public static NetworkCredential InvalidNetworkCredentials => new NetworkCredential("user1", "passwordxx");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Enterprise Scenario Testing

## What Are Enterprise Scenarios?
There are many definitions for enterprise scenarios. But generally in terms of how .NET Core networking APIs are used, enterprise scenarios are those networking scenarios that are fundamentally used by businesses (a.k.a enterprises) compared with consumers. As such, they use networking components, protocols, and security authentication mechanisms that are not used by most consumers using their home networking and Internet connections.

## Networking Components of Enterprise Scenarios
Enterprise scenarios typically see the following kinds of components/protocols/security:
* Although possibly connected to the Internet, most of the networking topology is internal facing. There is use of some internal “directory” service for authentication of connected computers and users. On Windows, this can include Windows Active Directory domains with computers being domain-controllers, domain-joined, or standalone computers. On Linux, this includes Kerberos realms using KDCs and participating member computers. With .NET Core being cross-platform, this now includes connections with multiple domains and realms with various cross trust between them.
* Authentication protocols such as NTLM, Kerberos and Negotiate. These are used more than Basic and Digest. Negotiate/Kerberos requires both client and server computers to be “joined” to a common trusted directory service.
* TLS/SSL extensively used.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TLS/SSL extensively used.

Really? TLS always seemed to be a secondary concern for these systems because of their intranet network topology. They also rely on the design of NTLM, Kerberos, and Negotiate to avoid credential theft without the additional overhead of TLS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. This document was written to help explain the overall concept of 'enterprise scenarios' to help developers new to the repo and these scenarios. I'll try to revise the text per your feedback.

* The use of proxy servers for HTTP/HTTPS communication. These usually include authenticated proxies where the proxy server demands authentication typically with Negotiate or NTLM authentication schemes.
* Complex DNS architectures using various A and CNAME (alias) records.
* Use of the NegotiateStream class. This is typically seen as part of using WCF client/server architecture.
* Impersonation/Delegation of credentials. This occurs frequently in middle-tier scenarios that involve a client computer talking with a middle-tier computer (such as a web server) which makes an outbound call to another computer such as a database server. In this case, the credentials of the client computer are delegated across the middle-tier computer so that the outbound call to the database server is made in the context of the client’s credentials.


## Running the tests
These tests need to be run in the dedicated Enterprise Test environment. This environment can be created on a local dev machine as long as Docker in installed. The enterprise test environment is a collection of Linux docker containers (client and servers) connected on a common docker network.

Set the DOTNET_RUNTIME_REPO_ROOT environment variable to the path on your dev machine (the host machine) where the repo is installed:

```
# Windows cmd.exe shell example
set DOTNET_RUNTIME_REPO_ROOT=s:\GitHub\runtime
```

```bash
# Linux bash shell example
export DOTNET_RUNTIME_REPO_ROOT=/home/me/GitHub/runtime
```

Now you can start up the enterprise system on your dev machine.

```
# Build test machine images
cd %DOTNET_RUNTIME_REPO_ROOT%\src\libraries\Common\tests\System\Net\EnterpriseTests\setup
docker-compose build

# Start up test machines and network
docker-compose up -d

# Connect to the 'linuxclient' container
docker exec -it linuxclient bash
```

At this point, you are in the linuxclient container. It is one "machine" which is part of an enterprise network.

Now build the repo as you would on a regular dev machine:

```bash
cd /repo
./libraries.sh
```

Now you can run the enterprise tests. Currently, there are tests for System.Net.Http and System.Net.Security. You can run them in the same way you already run tests in the repo.


(System.Net.Http example shown)

```bash
cd /repo/src/libraries/System.Net.Http/tests/EnterpriseTests
/repo/.dotnet/dotnet msbuild /t:rebuildandtest
```

You can exit from the container bash shell:

```bash
exit
```

But the containers stay running. You can re-connect to the client again anytime with the same command:

```
docker exec -it linuxclient bash
```

You can edit source code on your local machine and then rebuild and rerun tests as needed.

When you are done with the enterprise test network, you can shut it down from your local dev machine.

```
cd %DOTNET_RUNTIME_REPO_ROOT%\src\libraries\Common\tests\System\Net\EnterpriseTests\setup
docker-compose down
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM httpd:2.4

COPY ./common/krb5.conf /etc/

WORKDIR /setup
COPY ./apacheweb/*.sh ./
RUN chmod +x *.sh

# Prevents dialog prompting when installing packages
ARG DEBIAN_FRONTEND=noninteractive

# Install Kerberos client, apache Negotiate auth plugin, and diagnostics
RUN apt-get update && \
apt-get install -y --no-install-recommends libapache2-mod-auth-kerb procps krb5-user iputils-ping dnsutils nano

# Link apache2 kerb module to the right place since the apt-get install puts it in the wrong place for this docker image
RUN ln -s /usr/lib/apache2/modules/mod_auth_kerb.so /usr/local/apache2/modules

# Modify httpd.conf to add Negotiate auth as required
RUN echo "LoadModule auth_kerb_module modules/mod_auth_kerb.so" >> /usr/local/apache2/conf/httpd.conf && \
sed -i 's/Require all granted/AuthType Kerberos\nAuthName "Kerberos Login"\nKrbAuthRealm LINUX\.CONTOSO\.COM\nKrb5Keytab \/etc\/krb5\.keytab\nKrbMethodK5Passwd off\nRequire valid-user/' /usr/local/apache2/conf/httpd.conf

EXPOSE 80

ENTRYPOINT ["/bin/sh", "/setup/run.sh"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

cp /SHARED/apacheweb.keytab /etc/krb5.keytab

exec httpd -DFOREGROUND "$@"
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[libdefaults]
default_realm = LINUX.CONTOSO.COM

# The following krb5.conf variables are only for MIT Kerberos.
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true

# The following libdefaults parameters are only for Heimdal Kerberos.
fcc-mit-ticketflags = true

[realms]
LINUX.CONTOSO.COM = {
kdc = kdc.linux.contoso.com
admin_server = kdc.linux.contoso.com
}

[domain_realm]
.linux.contoso.com = LINUX.CONTOSO.COM
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
version: "3.7"

services:
kdc:
build:
context: ./
dockerfile: ./kdc/Dockerfile
image: kdc:latest
container_name: kdc
hostname: kdc
domainname: linux.contoso.com
dns_search: linux.contoso.com
volumes:
- shared-volume:/SHARED
networks:
- network1

apacheweb:
build:
context: ./
dockerfile: ./apacheweb/Dockerfile
image: apacheweb:latest
container_name: apacheweb
hostname: apacheweb
domainname: linux.contoso.com
dns_search: linux.contoso.com
volumes:
- shared-volume:/SHARED
networks:
network1:
aliases:
- apache.linux.contoso.com
depends_on:
- kdc

linuxclient:
build:
context: ./
dockerfile: ./linuxclient/Dockerfile
image: linuxclient:latest
container_name: linuxclient
hostname: linuxclient
domainname: linux.contoso.com
dns_search: linux.contoso.com
volumes:
- shared-volume:/SHARED
- ${DOTNET_RUNTIME_REPO_ROOT}:/repo
networks:
- network1
depends_on:
- apacheweb
- kdc

networks:
network1:
name: linux.contoso.com

volumes:
shared-volume:
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM ubuntu:18.04

COPY ./kdc/kadm5.acl /etc/krb5kdc/
COPY ./kdc/kdc.conf /etc/krb5kdc/
COPY ./common/krb5.conf /etc/

RUN mkdir /SHARED

WORKDIR /setup
COPY ./kdc/*.sh ./
RUN chmod +x *.sh

# Prevents dialog prompting when installing packages
ARG DEBIAN_FRONTEND=noninteractive

# Install KDC and diagnostic tools
RUN apt-get update && \
apt-get install -y --no-install-recommends krb5-kdc krb5-admin-server iputils-ping dnsutils nano

RUN ./setup-kdc.sh

VOLUME /SHARED

EXPOSE 88/tcp
EXPOSE 88/udp

ENTRYPOINT ["/bin/bash", "/setup/run.sh"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# /etc/krb5kdc/kadm5.acl -- Kerberos V5 general configuration.
#
# The user "root/admin" has full permissions
# Other users can inquire or list principals or policies
*/[email protected] *
*/*@LINUX.CONTOSO.COM il
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[kdcdefaults]
kdc_ports = 88

[realms]
LINUX.CONTOSO.COM = {
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
acl_file = /etc/krb5kdc/kadm5.acl
key_stash_file = /etc/krb5kdc/stash
kdc_ports = 88
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
master_key_type = des3-hmac-sha1
#supported_enctypes = aes256-cts:normal aes128-cts:normal
default_principal_flags = +preauth
}

[logging]
default = FILE:/var/log/kerberos/krb5.log
admin_server = FILE:/var/log/kerberos/kadmin.log
kdc = FILE:/var/log/kerberos/krb5lib.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

service krb5-kdc restart
service krb5-admin-server restart

cp /setup/*.keytab /SHARED
chmod +r /SHARED/*.keytab

# Keep the container running
tail -f /dev/null
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

# Kerbose Logging
mkdir -pv /var/log/kerberos/
touch /var/log/kerberos/krb5.log
touch /var/log/kerberos/kadmin.log
touch /var/log/kerberos/krb5lib.log

# Create Kerberos database
kdb5_util create -r LINUX.CONTOSO.COM -P password -s

# Start KDC service
krb5kdc

# Add users
kadmin.local -q "add_principal -pw password root/[email protected]"
kadmin.local -q "add_principal -pw password [email protected]"

# Add SPNs for services
kadmin.local -q "add_principal -pw password HTTP/apacheweb.linux.contoso.com"
kadmin.local -q "add_principal -pw password HOST/linuxclient.linux.contoso.com"
kadmin.local -q "add_principal -pw password HOST/localhost"
kadmin.local -q "add_principal -pw password NEWSERVICE/localhost"

# Create keytab files for other machines
kadmin.local ktadd -k /SHARED/apacheweb.keytab -norandkey HTTP/apacheweb.linux.contoso.com
kadmin.local ktadd -k /SHARED/linuxclient.keytab -norandkey HOST/linuxclient.linux.contoso.com
kadmin.local ktadd -k /SHARED/linuxclient.keytab -norandkey HOST/localhost
Loading