Posted: May 15th, 2008 | Author: telcor | Filed under: Information Technology (IT), Work | No Comments »
For two years now my testing platform has consisted of half a dozen physical machines (running a mixture of CentOS Linux and FreeBSD) and two powerful servers running VMware server. During that time I’ve had a couple instances to introduce Xen into the mix, but never on a permanent basis, usually due to time constraints. With two people my department now, I’ve had the opportunity to setup a more permanent Xen server. The Host itself is modest: AMD 3800+, 3 GiB RAM and A few hundred GB of Drive space.
The VMware server experience has soured me on the OS-in-a-loop-back-file method. Yes it can support LVM partitions, but only with some trickery, which I don’t want to do. Xen, however, needs no trickery.
With the help of LVM and images from jailme.org, I’ve been working out a nice routine which I will eventually automate. The process itself is rather simple:
- Create a new LVM partition for the OS ( e.g. lvcreate –size 20G -l OsName GroupName )
- Create a new LVM partition for swap ( e.g. lvcreate –size 1G -l OsSwap GroupName )
- Format the OS partition ( e.g. mkfs.ext3 -L OsPart /dev/GroupName/OsName )
- Format the Swap partition ( e.g. mkswap /dev/GroupName/OsSwap )
- Mount the Jailme.org image ( e.g. mount -o loop image.img /mnt )
- Mount the OS Partition ( e.g. mount /dev/GroupName/OsName /xen )
- Use rsync to copy the image contents to the OS Partition ( e.g. rsync -aP /mnt/* /xen )
- Make changes to some configuration files on the OS Partition
- Unmount the image and OS Partition
- Customize the Xen configuration file
- Start the image
My requirements only necessitate having a few setups like the above. My goal in automating the process is not just to remove the tedium, but to improve the speed. With a rough estimate, I think the above could be automated to occur in less than 10 minutes (accounting for load on the system).
Once that is automated, my next goal is to tackle taking ’snapshots’ of the Xen guest. I’m still undecided as to the exact method, although I am currently leaning toward creating a tarball of the partition.
Posted: March 23rd, 2007 | Author: telcor | Filed under: Information Technology (IT), PHP, WWW, Work | No Comments »
One of the problems inherent to using an Apache Module in a shared web hosting environment is the fact Apache modules gain all the permissions of Apache. Hence, using something like PHP as an Apache module can create serious security vulnerabilities. Since the PHP scripts run in the Apache context, users can easily cause problems (e.g. peeking in other users’ directories, overwritting other peoples files, etc). The easy way to solve this issue is to run PHP as CGI only. This means a user’s scripts will run in the context of the user’s permissions, rather than Apache’s.
Running as a CGI presents other problems. For example, the majority of 3rdparty PHP Applications assume one is running PHP as an Apache module. To use a script via CGI, one has to use something called a she-bang. The first line in the script is a special line that points to the binary that actually executes the script. Thus, if the PHP CGI binary is /usr/bin/php, then the first line in the script must be:
#!/usr/bin/php
Another (mainly superficial) problem is often CGI scripts must be placed in a cgi-bin directory. This means the URI to your blog won’t be www.example.com or blog.example.com but www.example.com/cgi-bin/blog.php or blog.example.com/cgi-bin/ Not exactly pretty. There are ways around that particular problem. There are still bigger problems, even running PHP as a CGI binary: how to lock down the user? You are essentially giving the user a lot of system access (the same is true when running Perl, bash, Ruby and other Scripting languages), how can we prevent a user from stomping all over the system? Even as CGI, the scripts are still executed as the Apache user.
Two common ways are PHPSuExec(*) and SuPHP. Both provide means of changing the UID/GID of the executing process to that of the end user, and many, many other safeguards. However, they both fail on one common problem with PHP: by default, PHP allows users to place their own php.ini file in their Document Root, which will be used to the exclusion of the system php.ini Thus if you have disabled various functions (e.g. dl, system, passthru, etc), a user can easily override it by dropping a blank php.ini file in his Document Root (typically ~/public_html)
Disabling user php.ini files
There are several ways to disable user php.ini files.
- Configure php with –with-config-file-path=/usr/local/lib –with-config-file-scan-dir=/usr/local/lib
- ( Won’t work with PHP 4.4.x) Install the Zend Optimizer
- ( Won’t work with PHP 4.4.x) Create a wrapper script
As noted, only the first option works for all modern versions of PHP. The directory path provided should match where your system php.ini file is located. Once compiled with these options, PHP is essentially “jailed” into using a php.ini file where configure stipulated. One odd thing to note with this, phpinfo() will lie. Try the following in a user account:
- In your user Document Root directory, create an empty file named php.ini\
- In a separate file, place <?php phpinfo(); ?>
- Access the phpinfo file via your web browser
- Note that phpinfo() reports it is using the php.ini file located in your Document Root
An easy way to verify which is being used is to disable a function in the system php.ini file (such as ini_get). In the user php.ini, override that (disable_functions=). Create a short script that tries to use the disabled function. You’ll receive an error stating the function is disabled for security purposes.
What about the other methods? In PHP 5.2.x, installing the Zend Optimizer forces PHP to use the one stipulated in the Zend configuration, thus overriding the user php.ini file. And the wrapper script?
Locate your PHP CGI binary (we’ll use /usr/bin/php as an example) and rename it to php-cgi (thus /usr/bin/php-cgi). In the same directory, create a file named php. Give it the same permissions as php-cgi and insert the following contents:
#!/bin/sh/usr/bin/php-cgi -c /usr/local/lib/php.ini
The -c parameter instructs PHP to use the configuration file stipulated and ignore all others. Astute readers/users will notice this doesn’t filter out the possiblility of a user passing -c/path/to/user/php.ini If you are concerned with that, a script similar to the following will work (as contents of /usr/bin/php):
#!/usr/bin/perl --use strict;use warnings;die '-c not allowed' if grep { $_ } map { $_ eq '-c' } @ARGV;exec( qw(/usr/bin/php-cgi -c /usr/local/lib/php.ini), @ARGV );
Now, if a user attemps to pass -c/path/to/user/php.ini to the script, it will die. If done via a web-accessible script, Apache will return a 500 error and the die message will be in the error_log The use of Perl is just an example, you could do something in BASH, Python, C or whatever. Unfortunately, PHP 4.4.x ignores -c when compiled as a CGI binary, hence this trick only works on PHP 5.