Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A55A2B9A-830F-4330-A0E7-02A9FB30ABD2}</ProjectGuid>
<OutputType>Library</OutputType>
<UnsupportedPlatforms>OSX</UnsupportedPlatforms>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetsWindows)' == 'true' and '$(ProjectJson)' == '' ">
<ProjectJson>win/project.json</ProjectJson>
Expand Down Expand Up @@ -82,16 +83,23 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="IdentityValidator.Unix.cs" />
<None Include="..\Scripts\kdc.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup Condition=" '$(TargetsLinux)' == 'true' ">
<None Include="..\Scripts\setup-kdc.sh">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\Scripts\krb5.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\Scripts\kdc.conf.ubuntu">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\Scripts\kdc.conf.centos">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: indentation on all of this

<ItemGroup>
<ProjectReference Include="..\..\src\System.Net.Security.csproj">
<Project>{89F37791-6254-4D60-AB96-ACD3CCA0E771}</Project>
Expand Down
11 changes: 11 additions & 0 deletions src/System.Net.Security/tests/Scripts/kdc.conf.centos
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88

[realms]
TEST.COREFX.NET = {
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
}
16 changes: 16 additions & 0 deletions src/System.Net.Security/tests/Scripts/kdc.conf.ubuntu
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[kdcdefaults]
kdc_ports = 750,88

[realms]
TEST.COREFX.NET = {
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 = 750,88
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this line required here? It feels like it should be just using the equivalent one from [kdcdefaults], no?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is default kdc.conf file generated with the KDC installation on Ubuntu/Debian (With required realm name changed).
kdcdefaults section has global configuration parameters, applied to all realms defined.
However, we can still override those by defining realm-specific parameters.
In this case, however, realm-specific parameter doesn't add any value.

max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
master_key_type = des3-hmac-sha1
supported_enctypes = aes256-cts:normal arcfour-hmac:normal des3-hmac-sha1:normal des-cbc-crc:normal des:normal des:v4 des:norealm des:onlyrealm des:afs3
default_principal_flags = +preauth
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A lot of lines that are present in the ubuntu file are missing from the centos one. Why?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

These are default kdc.conf files generated by the MIT KDC installation. Yes, the file on CentOS/RHEL is significantly different than that in Ubuntu/Debian out of the box.

}
227 changes: 180 additions & 47 deletions src/System.Net.Security/tests/Scripts/setup-kdc.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#!/bin/bash
#!/usr/bin/env bash

OS=`cat /etc/os-release | grep "PRETTY_NAME" | sed 's/PRETTY_NAME=//g' | sed 's/["]//g' | awk '{print $1}'`
OS=`cat /etc/os-release | grep "^ID=" | sed 's/ID=//g' | sed 's/["]//g' | awk '{print $1}'`
echo -e "Operating System: ${OS}\n"

realm="TEST.COREFX.NET"

principal1="HOST/host.test.corefx.net"
principal2="HTTP"
principal1="TESTHOST/testfqdn.test.corefx.net"
principal2="TESTHTTP"
krb_user="krb_user"
password="password"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If someone runs this script, is there any danger that it'll open their machine up to any kind of attack? e.g. could it give someone with these fake creds access to anything on their machine?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

+1 on @stephentoub's question. I'm not convinced creating even low privilege accounts is a safe thing to do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This will enable getting a Kerberos ticket for the TEST.COREFX.NET realm but there won't be any server that would trust that ticket.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@morganbr can also chime in if we have missed something

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

but there won't be any server that would trust that ticket.

Including this machine? My concern isn't that some other machine would trust these credentials, but rather than this machine would trust them, and that, for example, after I've run this script on my Linux machine that someone else can use these wide-open credentials to gain some kind of access, even limited access, to my Linux machine.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Right.. I meant even this machine. @rahulkotecha there is no home directory etc for this user but you should verify if telnet, SSH etc are kerberized by default and can somehow allow a login

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Verified on Ubuntu, Debian, CentOS and RHEL.
SSH, telnet are not kerberized by default, hence won't allow the kdc users to login through either of there protocols.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for confirming, @rahulkotecha They probably all need passwd entry that maps to the Kerberos principal. One minor change we should make is to use non-standard service principal names. eg. change HTTP to TestHTTP etc. This will further reduce probability of a regular service using the service principals we are creating.

cc: @joshfree
@morganbr , @joshfree, can you recommend some Unix security expert who can validate our thinking?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I know steps have been taken to mitigate concerns related to this, but are there additional ones we can take? For example, do these credentials need to be hard coded, or could the setup script generate them randomly?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We couldn't think of a way to create a random password that the test case also would be aware of. @stephentoub, if the test case is always running elevated, we can store a random password in a well-known file which requires root access for reading. But if we expect the 3rd party dev experience running tests outside CI to run non-elevated, this would be an issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if the test case is always running elevated, we can store a random password in a well-known file which requires root access for reading. But if we expect the 3rd party dev experience running tests outside CI to run non-elevated, this would be an issue.

Right now the password is in a web page for the whole world to see. Even if a random one is written to a local file that doesn't require root access, isn't that still much better?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed :) @rahulkotecha I think we should make this change

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Filed #6329 for this to take care of in a followup PR


Expand All @@ -15,83 +16,215 @@ kdb5_util="kdb5_util"
add_principal_cmd="add_principal -pw ${password}"

krb_conf="krb5.conf"
kdc_conf="kdc.conf"
krb_conf_location="/etc/krb5.conf"
keytabfile="/etc/krb5.keytab"

# TODO: These locations varies for different distros, Set the values conditianally
krb_conf_location="/etc/"
kdc_conf_location="/etc/krb5kdc/"
database_file="/var/lib/krb5kdc/principal*"
PROGNAME=$(basename $0)
usage()
{
echo "This script must be run with super-user privileges."
echo "Usage: ${PROGNAME} [-h|--help] [-y|--yes] [-u|--uninstall]";
}

kdc_setup()
# Cleanup config files and uninstall KDC
clean_up()
{
#Create/copy krb5.conf in /etc/ and kdc.conf in /etc/krb5kdc/
echo "Stopping KDC.."
if pgrep krb5kdc 2> /dev/null; then killall krb5kdc ; fi

echo "Removing config files"
if [ -f ${krb_conf_location} ]; then
rm -f ${krb_conf_location}
fi

case ${OS} in
"ubuntu" | "debian")
kdc_conf_location="/etc/krb5kdc/kdc.conf"
dpkg -s krb5-kdc >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Uninstalling krb5-kdc"
apt-get -y purge krb5-kdc
fi
;;

"centos" | "rhel")
kdc_conf_location="/var/kerberos/krb5kdc/kdc.conf"
yum list installed krb5-server >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Uninstalling krb5-server"
yum -y remove krb5-server
fi
;;

*)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we print something out if the OS wasn't recognized?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, will add an echo statement.

echo "This is an unsupported operating system"
;;
esac

if [ -f ${kdc_conf_location} ]; then
rm -f ${kdc_conf_location}
fi

echo "Cleanup completed"
}

error_exit()
{
echo "${1:-"Unknown Error"}"
echo "Aborting"
clean_up
exit 1
}

# Common function across linux distros to configure KDC post installation
configure_kdc()
{
echo "Stopping KDC.."
if pgrep krb5kdc 2> /dev/null; then killall krb5kdc ; fi

# Remove database files if exist
rm -f ${database_files}

# Create/copy krb5.conf and kdc.conf
echo "Copying krb5.conf and kdc.conf.."
sudo /bin/cp ${krb_conf} ${krb_conf_location}
sudo /bin/cp ${kdc_conf} ${kdc_conf_location}
cp ${krb_conf} ${krb_conf_location} || \
error_exit "Cannot copy ${krb_conf} to ${krb_conf_location}"

cp ${kdc_conf} ${kdc_conf_location} || \
error_exit "Cannot copy ${kdc_conf} to ${kdc_conf_location}"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What's the state of the machine if one of these errors out? Will uninstall successfully undo any changes made thus far, even if the install wasn't complete? I just want to make sure that a dev can get back to a clean state if something goes wrong part way through install.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, there is cleanup procedure in place which, upon occurrence of an error, will revert the changes made to the system thus far (config files, installation of kdc, etc.)


echo "Creating KDC database for realm ${realm}.."
sudo ${kdb5_util} create -r ${realm} -P ${password} -s
${kdb5_util} create -r ${realm} -P ${password} -s || \
error_exit "Cannot create KDC database for realm ${realm}"

echo "Adding principal ${principal1}.."
sudo ${kadmin} -q "${add_principal_cmd} ${principal1}@${realm}"
${kadmin} -q "${add_principal_cmd} ${principal1}@${realm}" || \
error_exit "Cannot add ${principal1}"

echo "Adding principal ${principal2}.."
sudo ${kadmin} -q "${add_principal_cmd} ${principal2}@${realm}"
${kadmin} -q "${add_principal_cmd} ${principal2}@${realm}" || \
error_exit "Cannot add ${principal2}"

echo "Adding user ${krb_user}.."
sudo ${kadmin} -q "${add_principal_cmd} ${krb_user}@${realm}"
${kadmin} -q "${add_principal_cmd} ${krb_user}@${realm}" || \
error_exit "Cannot add ${krb_user}"

echo "Exporting keytab for ${principal1}"
sudo ${kadmin} -q "ktadd ${principal1}@${realm}"
${kadmin} -q "ktadd -norandkey ${principal1}@${realm}" || \
error_exit "Cannot export kytab for ${principal1}"

echo "Exporting keytab for ${principal2}"
sudo ${kadmin} -q "ktadd ${principal2}@${realm}"
${kadmin} -q "ktadd -norandkey ${principal2}@${realm}" || \
error_exit "Cannot export kytab for ${principal2}"

echo "Exporting keytab for ${krb_user}"
sudo ${kadmin} -q "ktadd ${krb_user}@${realm}"
${kadmin} -q "ktadd -norandkey ${krb_user}@${realm}" || \
error_exit "Cannot export kytab for ${krb_user}"
}

# check the invoker of this script
if [ $EUID -ne 0 ]; then
usage
exit 1
fi

# Parse command-line arguments
TEMP=`getopt -o hyu --long help,yes,uninstall -n 'test.sh' -- "$@"`
[ $? -eq 0 ] || {
usage
exit 1
}
eval set -- "$TEMP"
uninstall=0
force=0
while true; do
case $1 in
-h|--help) usage; exit 0;;
-y|--yes) force=1; shift ;;
-u|--uninstall) uninstall=1; shift;;
--) shift; break;;
*) usage; exit 1;;
esac
done

# Uninstallation
if [ $uninstall -eq 1 ]; then
if [ $force -eq 0 ]; then
echo "This will uninstall KDC from your machine and cleanup the related config files."
read -p "Do you want to continue? ([Y]es/[N]o)? " choice
case $(echo $choice | tr '[A-Z]' '[a-z]') in
y|yes) clean_up;;
*) echo "Skipping uninstallation";;
esac
else
clean_up
fi
exit 0
fi

echo "Removing existing database"
sudo rm -rf ${database_file}
# Installation
if [ $force -eq 0 ]; then
read -p "This will install KDC on your machine and create KDC principals. Do you want to continue? ([Y]es/[N]o)? " choice
case $(echo $choice | tr '[A-Z]' '[a-z]') in
y|yes) ;;
*) echo "Skipping installation"; exit 0;;
esac
fi

case ${OS} in
"Ubuntu")
"ubuntu" | "debian")
kdc_conf="kdc.conf.ubuntu"
kdc_conf_location="/etc/krb5kdc/kdc.conf"
database_files="/var/lib/krb5kdc/principal*"

dpkg -s krb5-kdc >/dev/null 2>&1
if [ $? -ne 0 ]
then
if [ $? -ne 0 ]; then
echo "Installing krb5-kdc.."
sudo DEBIAN_FRONTEND=noninteractive apt-get -y install krb5-kdc krb5-admin-server
export DEBIAN_FRONTEND=noninteractive
apt-get -y install krb5-kdc krb5-admin-server
if [ $? -ne 0 ]; then
echo "Error occurred during installation, aborting"
exit 1
fi
else
echo "krb5-kdc already installed.."
exit 2
fi

echo "Stopping KDC.."
if pgrep krb5kdc 2> /dev/null; then killall krb5kdc ; fi
if pgrep kadmind 2> /dev/null; then killall kadmind ; fi

kdc_setup
configure_kdc
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If user already has krb5 installed this script will be a no-op. In such cases, the tests may fail (the user's krb5.conf may not contain the principals needed for the test)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a way to prompt the user to overwrite their set up if that's actually what they want?

What about an uninstall, that undoes all of the configuration done in the script?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Prompting will not be possible due to the automated nature.

For uninstall, @stephentoub should we add an argument to the script? Then in #6139 should we also do an uninstall each time? (Note that always cleaning up will add to the time when devs run NegotiateStream tests locally)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Prompting will not be possible due to the automated nature.

That's not necessarily true. There are many utilities that prompt, for example, unless you pass a /force or /Y or some such flag that says "I know what I'm doing, I automatically say 'yes' to any prompt, so don't prompt me".

For uninstall, @stephentoub should we add an argument to the script?

Yes, please.

Then in #6139 should we also do an uninstall each time?

If running the tests does an automatic install, then they should also automatically uninstall. Otherwise, running the tests leaves the box in a state different than it started. It should also be possible to run the uninstall manually and clean up any vestiges of the previous install.

Note that always cleaning up will add to the time when devs run NegotiateStream tests locally

We should make it so that it only uninstalls if it needed to install. That way, if a developer is working on this library and has manually run the install script, no extra install/uninstall time is taken in each run. If it's someone who's just running a full test pass or otherwise running the tests locally, and they don't have things set up appropriately, the tests will do the install and uninstall and their box will (hopefully) be left clean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Makes sense. Thanks for the idea about force switch

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@stephentoub we are not actually overwriting user's setup. If the kdc is already installed, we are assuming that the machine is already setup with required users for the testing (through earlier runs of the script). If this assumption is indeed correct, then we might not require the force switch.
Let me know if this assumption is correct.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@rahulkotecha the force switch is also to let a dev running script outside CI to see some prompts before KDC config. Having the force switch allows the script to be run without prompts from test class setup


echo "Starting KDC.."
sudo ${krb5kdc}

${krb5kdc}
;;

"centos" | "rhel")
kdc_conf="kdc.conf.centos"
kdc_conf_location="/var/kerberos/krb5kdc/kdc.conf"
database_files="/var/kerberos/krb5kdc/principal*"

"Debian")
echo "This is a Debian system"
;;

"CentOS")
echo "This is a CentOS system"
;;

"Red Hat")
echo "This is a RedHat system"
yum list installed krb5-server >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Installing krb5-server.."
yum -y install krb5-server krb5-libs
if [ $? -ne 0 ]; then
echo "Error occurred during installation, aborting"
exit 1
fi
else
echo "krb5-server already installed.."
exit 2
fi

configure_kdc

echo "Starting KDC.."
systemctl start krb5kdc.service
systemctl enable krb5kdc.service
;;

*)
echo "This is an Unknown system"
echo "This is an unsupported operating system"
;;
esac
sudo chmod +r ${keytabfile}

chmod +r ${keytabfile}