Showing posts with label Web servers. Show all posts
Showing posts with label Web servers. Show all posts

Jun 17, 2012

Apache performance tuning: security (II)

This is the second part of the article Apache performance tuning: security (I).

Disable DNS reverse

Apache has a special directive, HostnameLookups, that if it is set on, the web server will always try to resolve the IP address for each connection. This situation adds an unnecessary overload to the system, because if you need to know the names of the machines involved, you can use the logresolve tool later.

[root@localhost ~]# cat /etc/httpd/conf/httpd.conf
...
HostnameLookups Off
...

Unnecessary information provided by Apache

Disable the information introduced by Apache about its version and the kind of operating system on where it is running, both HTTP response headers from the server and error messages.

[root@localhost ~]# cat /etc/httpd/conf/httpd.conf
...
ServerTokens Prod
ServerSignature Off
...

Customize error messages

By using the ErrorDocument directive, you can pick out which error message should be showed the client when a particular error takes place.

[root@localhost ~]# cat /etc/httpd/conf/httpd.conf
...
ErrorDocument 404 "Error 404 !!!"
ErrorDocument 500 /error_500.html

Limit HTTP access methods

The HTTP protocol defines eight different methods: GET, POST, CONNECT, etc. You can use the Limit directive in order to restrict the effect of the access controls to the aforementioned HTTP methods, for instance avoiding that one of this methods works on a directory or virtual host.

[root@localhost ~]# cat /etc/httpd/conf/httpd.conf
...
<Limit POST>
    Order deny,allow
    Deny from all
</Limit>
...

The preceding configuration will not allow to upload any file to the server, returning a 403 Forbidden error if you try it.

Set the right permissions to the Apache binary

Every user who is not the owner or does not belong to the Apache group, cannot access the Apache executable file.

[root@localhost ~]# chown o-rwx /usr/sbin/httpd

Remove the welcome message

The welcome message is a web page which is displayed to the user when no index.html document exists in the DocumentRoot of the server, and the indexation is disabled (Options -Indexes).

[root@localhost ~]# rm /etc/httpd/conf.d/welcome.conf

Perform a security analysis through Nikto

Nikto is an open source web server scanner (developed in Perl) which carries out comprehensive tests against web servers for multiple items, including around 6400 potentially dangerous files/CGIs, checks for outdated versions of over 1200 servers, and version specific problems on over 270 servers. It also verifies for server configuration items such as the presence of multiple index files, HTTP server options, and will attempt to identify installed web servers and software.

[root@localhost ~]# wget --no-check-certificate https://cirt.net/nikto/nikto-2.1.4.tar.gz

[root@localhost ~]# tar xvzf nikto-2.1.4.tar.gz ; cd nikto-2.1.4

[root@localhost nikto-2.1.4]# ./nikto.pl -host localhost
- ***** SSL support not available (see docs for SSL install) *****
- Nikto v2.1.4
---------------------------------------------------------------------------
+ Target IP:          127.0.0.1
+ Target Hostname:    localhost
+ Target Port:        80
+ Start Time:         2012-05-32 22:16:13
---------------------------------------------------------------------------
+ Server: Apache/2.2.15 (CentOS)
+ Apache/2.2.15 appears to be outdated (current is at least Apache/2.2.17). Apache 1.3.42 (final release) and 2.0.64 are also current.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS, TRACE 
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ OSVDB-3268: /icons/: Directory indexing found.
+ OSVDB-3233: /icons/README: Apache default file found.
+ 6448 items checked: 1 error(s) and 5 item(s) reported on remote host
+ End Time:           2012-05-32 22:16:39 (26 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Nikto also has other useful option that you can take a look at. In addition, you can run Nikto with the "-update" option, so as to update databases and plugins from CIRT.net.

[root@localhost nikto-2.1.4]# ./nikto.pl -update


May 31, 2012

Apache performance tuning: security (I)

Let's get started by remembering the series of articles published about Apache performance tuning:

  • Apache performance tuning: dynamic modules (I and II).
  • Apache performance tuning: directives (I and II).
  • Apache performance tuning: benchmarking (I)

In this post, I am going to talk about the points related to security, which you have to take into account when you are setting up an Apache installation.

Restrictions for the Apache user

The Apache user must not be able to log into the system. If you take a look at both passwd and shadow files, you will be able to appreciate that no shell is assigned to him (/sbin/nologin), and the field reserved for the password will contain "!!". That means that the Apache user will not be able to log on the system (he is blocked).

[root@localhost ~]# cat /etc/passwd | grep apache
apache:x:48:48:Apache:/var/www:/sbin/nologin

[root@localhost ~]# cat /etc/shadow | grep apache
apache:!!:15490::::::

Restrictions for the system root

You have to prevent that the system root (/) is accessible through the web server. It is also better to disable all options on the root directory (Options none)  and control what directives can be used in the .htaccess file by means of the AllowOverride directive.

[root@localhost ~]# cat /etc/httpd/conf/httpd.conf
...
<Directory />
    Order deny,allow
    Deny from all
    Options none
    AllowOverride none
</Directory>
...

If you define the root directory with these characteristics, then you will have to add to each directory the allowed options.

Hiding a directory or a file

Perhaps you can have a directory completely indexed and in turn, it contains different subdirectories, but you do not want to make visible a concrete directory (hidden) and you desire that it is reachable only when you type its URL. For this purpose, you have to use the IndexIgnore option.

[root@localhost ~]# cat /etc/httpd/conf/httpd.conf
...
<Directory "/var/www/html/data">
    Options Indexes
    IndexIgnore status
    IndexIgnore *.bpm
    ...
</Directory>
...

In the previous example, Apache will keep hidden the status directory and all files with bmp extension included in the /var/www/html/data directory.


Apr 9, 2012

Apache performance tuning: benchmarking

Let's continue with the series of articles about Apache performance tuning. Remember that in the previous ones, I approached the topics about dynamic modules (I and II) and directives (I and II).

So after reviewing the directives which allow to fit the global configuration of Apache, I am going to focus on a couple of tools used to adjust the values of those directives, based on the available hardware and the kind of service which wants to be offered.

The first application to be presented is ab (Apache benchmark), normally utilized in order to get hold of the performance values which the web server will be able to achieve. It is designed to give an impression of how your current Apache server works, specially by showing how many requests per second which is able to serve.

This tool puts forward multiple options, but the normal operation format so as to carry out performance tests will be as follows (there are other many useful options that you can check by going to the man):

[root@localhost ~]# ab -c concurrency -n request [-k] [http[s]://]hostname[:port]/path

Through the '-c' option is specified the number of multiple requests to perform at once, that is to say, it stands for the concurrence whereby the web server will be requested. For example, '-c 100' means that one hundred users will be launching requests simultaneously.

By means of the '-n' option, you may establish the number of requests to perform for the benchmarking session, that is, the total number of requests which will be run. For instance, '-c 20 -n 1000' means that 50 groups of 20 requests per group will be executed. And with the '-k' option, the HTTP keepalive feature is enabled. In this way, it is possible to handle multiple requests within one HTTP session.

[root@localhost ~]# ab -c 200 -n 1000 http://localhost/index.html
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Apache/2.2.15
Server Hostname:        localhost
Server Port:            80

Document Path:          /index.html
Document Length:        1656 bytes

Concurrency Level:      200
Time taken for tests:   1.696 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      1934625 bytes
HTML transferred:       1664280 bytes
Requests per second:    589.67 [#/sec] (mean)
Time per request:       339.175 [ms] (mean)
Time per request:       1.696 [ms] (mean, across all concurrent requests)
Transfer rate:          1114.05 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    8  10.0      4      38
Processing:    14  163 353.1     85    1645
Waiting:       11  160 353.2     81    1638
Total:         51  171 354.7     89    1660

Percentage of the requests served within a certain time (ms)
  50%     89
  66%     92
  75%     94
  80%     95
  90%    102
  95%   1637
  98%   1645
  99%   1651
 100%   1660 (longest request)

The most important values output by ab are Failed requests, Requests per second and Time per request. As you can distinguish in the above example, all requests have been completed successfully, with an average of 589 requests per second and an average time of 1.696 ms for each request.

Another interesting tool used to assess the performance of a web server is curl, which takes care of finding out the response time for an unique request of a single element. Curl transfers data from or to a server, by using one of the supported protocols (HTTP, HTTPS, FTP, etc.).

[root@localhost ~]# curl -o /dev/null -s -w %{time_connect}:%{time_starttransfer}:%{time_total} http://localhost/index.html
0.002:0.003:0.004

In the preceding example, the time taken to process the request and start sending data has been 0.002 - 0.001 = 0.001 sg, and the time for sending 0.004 - 0.003 = 0.001 sg.


Feb 19, 2012

Apache performance tuning: directives (II)

Let's carry on with the second part of the article Apache performance tuning: directives (I).

If you take a look at the previous output, you may identify that the first process is the parent and the other ones, its children. The most important column is RSS (Resident Set Size), whereby you can see that the size of memory taken up by a child process is around 2 MB. Thus, you might work out the maximum number of Apache processes which can be simultaneously running on your system:

MaxClients = 338 MB / 2 MB = 169

This value is relative and never should be taken into account exactly. You have to consider that at any given time, other applications running on the system (mail, FTP, database, etc.) can ask for free memory. So in the preceding case, it would be reasonable to grab 200 MB instead of 338 MB. Furthermore, you must think that is not the same task to serve dynamic than static content.

If all processes are busy, Apache launches a series of spare processes (MinSpareServers). If a given time many processes are idle, these are removed with the aim of not exceeding a maximum number of spare processes (MaxSpareServers). In general, it must be satisfied that MinSpareServers ≤ StartServer ≤ MaxSpareServers, and MaxSpareServers should be 50% higher than MinSpareServers.

When a process has handled too many requests (MaxRequestsPerChild), this is deleted and another one is created again. An optimum value for MaxRequestsPerChild is 4000, although it is appropriate to fit it based on the data served.

What happens if a connection does not respond or keeps inactive indefinitely? A connection is another resource for the system and as such, must be freed up in case of not being used. The default timeout is usually very high (300 seconds). In order to enhance the server performance is useful to turn down this value to 20 (nowadays, the speed of the networks is huge, and it does not make sense to set such a high Timeout).

Lastly, we are going to treat an important issue for a web server: the persistence. When a web page is loaded, it is normal that the web browser establishes an only TCP connection and downloads all web elements, by carrying out multiple requests over the same connection.

So as to manage this feature, Apache provides three different parameters in its configuration file.

  • KeepAlive: enables (On) or disables (Off) persistent connections.

  • MaxKeepAliveRequests: maximum number of requests allowed on a persistent connection.

  • KeepAliveTimeout: amount of time the server will keep an inactive persistent connection before closing it.

It is recommended to use a very high value for the KeepAliveTimeout parameter (2 or 3 seconds). In respect of MaxKeepAliveRequests, will depend on the amount of content that web pages have on average, but it should not usually exceed 1000.


Feb 13, 2012

Apache performance tuning: directives (I)

In this article about Apache performance tuning, I am going to deal with some Apache directives. Remember that in the previous articles (I and II), I focused on the Apache modules, and we learnt on the one hand, that we can reduce the memory used by each process by removing those modules which are not necessary, and in this way, they will be lighter. And on the other, if we take those unused modules out, we will have less software exposed to possible attacks.

One of the most important tasks when we are setting Apache up is to fit its directives, which allow to control the overall running of the web server. These directives always depend on the available hardware, as well as the type of content that you want to serve. They are located inside the httpd.conf file; bellow, I will show you the most meaningful directives.

  • StartServers: number of child server processes created on startup. This value is related to the initial HTTP load of the machine, whether there are another configured services, and so on. For example, if the computer only works as a web server, there is no problem to start with 50 processes, but if there are other running services such as FTP, mail, database, etc., and in addition, it runs low on computational resources, we should start with a small number of active processes, and afterwards, on real time, Apache itself would have to launch the needed ones.

  • MaxClients: maximum number of simultaneous processes that can be running at the same time.

  • ServerLimit: maximum number of processes for the MaxClients parameter.

  • MinSpareServers: minimum number of idle child server processes.

  • MaxSpareServers: maximum number of idle child server processes.

  • MaxRequestsPerChild: maximum number of requests that an individual child server will handle during its life.

  • Timeout: amount of time the server will keep an inactive connection before closing it.

When Apache is started, several processes are created (StartServers) in order to listen for potential connections. When a request reaches the server, this is attended by a child process, and then, the process switches to idle state, waiting for new connections. If at a given time the number of requests is greater than the number of available processes (MaxClients), these requests are queued. Must be satisfied that MaxClients ≤ ServerLimit.

We can work out the maximum number of httpd processes that our system can run based on the available memory. You have to divide the free memory of the server by the amount of memory taken by an unique Apache process.

So as to calculate the free memory of the system, you can use the following command.

[root@centos ~]# cat /proc/meminfo | grep MemFree
MemFree:          346492 kB

And in order to find out the amount of memory grabbed by an Apache process, you may run the next order.

[root@centos ~]# ps -ylC httpd
S   UID   PID  PPID  C PRI  NI   RSS    SZ WCHAN  TTY          TIME CMD
S     0  1870     1  0  80   0  3404  2792 -      ?        00:00:00 httpd
S    48  1873  1870  0  80   0  2072  2792 -      ?        00:00:00 httpd
S    48  1874  1870  0  80   0  2072  2792 -      ?        00:00:00 httpd
S    48  1875  1870  0  80   0  2072  2792 -      ?        00:00:00 httpd


Dec 22, 2011

Apache performance tuning: dynamic modules (II)

Let's continue with the second part of the article titled Apache Performance tuning: dynamic modules (I). Remember that this paper is aimed at reviewing the different modules belonging to Apache, so as to determine whether they are useful for our requirements. To that end, we will be able to fit the amount of memory used by Apache processes.

The most important point is to be aware of that one only process consumes little memory, but if our Apache installation requires lots of processes, the total memory grabbed by Apache will be huge. So if we get hold of turning down the initial memory with which a process is created, afterwards it will run lighter and besides, we will have that free memory available in order to be allocated for other things.

mod_ext_filter

Forwards the response body to an external program before sending it out to the client.

# LoadModule ext_filter_module modules/mod_ext_filter.so

mod_include

Filters files before delivering them to the client.

# LoadModule include_module modules/mod_include.so

mod_info

Provides a comprehensive overview of the web server configuration.

# LoadModule info_module modules/mod_info.so

mod_ldap

Improves the performance of websites by pooling LDAP connections and caching responses.

# LoadModule ldap_module modules/mod_ldap.so

mod_logio

Logs the input and output number of bytes received/sent per request.

# LoadModule logio_module modules/mod_logio.so

mod_proxy

Puts into action a a proxy/gateway.

# LoadModule proxy_module modules/mod_proxy.so
# LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
# LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
# LoadModule proxy_http_module modules/mod_proxy_http.so
# LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
# LoadModule proxy_connect_module modules/mod_proxy_connect.so

mod speling

Tries to correct erroneous URLs that users could have typed by overlooking capitalization and allowing up to one misspelling.

# LoadModule speling_module modules/mod_speling.so

mod_status

Provides statistics about the activity and performance of the web server.

# LoadModule status_module modules/mod_status.so

mod_suexec

Allows CGI scripts to run as a concrete user and group.

# LoadModule suexec_module modules/mod_suexec.so

mod_userdir

Allows user directories can be accessed through the web server.

# LoadModule userdir_module modules/mod_userdir.so

mod_usertrack

Logs user activity.

# LoadModule usertrack_module modules/mod_usertrack.so

After disabling these modules, the memory used by one Apache process (and owned by apache user) went from 2.02 to 1.46 MB, that is to say, we have gained around 0.6 MB. If you take into account that a large number of processes can be running on the system at any given time, the saved memory might be appreciable. In addition, you have to consider that from now on, a process is much lighter, with what its startup and performance will be much better.


Dec 14, 2011

Apache performance tuning: dynamic modules (I)

Apache is a cross-platform, modular and open source web server, widely used around the world for its quality, robustness and stability. But like most of the applications, it is installed with a default configuration which is not the most adequate. And I am going to say more: I have never seen an Apache installation where the administrator has set it up correctly later.

During several articles, you are going to learn how to properly optimize Apache, in order to achieve the best performance. The tests will be carried out on CentOS 6.2 (32 bits) with Apache 2.2.15. I am going to break up this first article relative to dynamic modules in two separate parts.

Apache has got two main operating modes, also known as multi-processing modules (MPMs):

  • Prefork: an unique Apache process (httpd) launchs child processes which take care of listening for potential connections and serving them. Apache keeps several idle processes ready to attend incoming requests. Thereby, a client does not need to wait for new children are forked. Another advantage of this operation mode is that if there is a problem in any process, this will not affect other processes (each child is independent of the rest). 

  • Worker: as in the previous case, an only control process creates several child processes, and in turn, each child process handles a listener thread which passes the inbound connections to other server threads managed as well by the same child process. This mode is faster and more scalable, but in contrast, it is more fault tolerant (several threads share the same memory area, and if there is any problem in the parent, it will involve the rest).

You can install Apache either by compiling it from its source code or by getting directly the binary file from a repository. I for one prefer this second option, because in this way, any kind of update (security or bugfix) will be able to be applied without compiling it again.

A typical installation of Apache via yum comes with the following pre-compiled modules. As you may appreciate, prefork will be the default operating mode (you can change this by modifying the /etc/sysconfig/httpd file).

[root@centos ~]# httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c

It is basic to know the funcionality of each module so as to figure out if it can be left out. Then we are going to put forward what modules can be ruled out in the most of the cases. Also point out that all directives showed below, are included into the Apache configuration file (httpd.conf). In many cases, the related modules will be also disabled, aside from the principal one.

mod_actions

Allows the execution of CGI scripts based on the MIME content type and the request method.

# LoadModule actions_module modules/mod_actions.so

mod_auth_basic

Limits access to certain users by using HTTP Basic Authentication. I usually disable its dependencies.

LoadModule auth_basic_module modules/mod_auth_basic.so
# LoadModule authn_file_module modules/mod_authn_file.so
# LoadModule authn_alias_module modules/mod_authn_alias.so
# LoadModule authn_anon_module modules/mod_authn_anon.so
# LoadModule authn_dbm_module modules/mod_authn_dbm.so
# LoadModule authn_default_module modules/mod_authn_default.so
# LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
# LoadModule authn_dbd_module modules/mod_authn_dbd.so

mod_auth_digest

Limits access to certain users by using MD5 Digest Authentication.

# LoadModule auth_digest_module modules/mod_auth_digest.so

mod_authz_*

Limits access to certain groups based on different origins (DBM or plaintext files, hostname or IP address, etc.). I get used to remove all less mod_authz_host.

LoadModule authz_host_module modules/mod_authz_host.so
# LoadModule authz_user_module modules/mod_authz_user.so
# LoadModule authz_owner_module modules/mod_authz_owner.so
# LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
# LoadModule authz_dbm_module modules/mod_authz_dbm.so
# LoadModule authz_default_module modules/mod_authz_default.so

mod_cache

Manages the content cache.

# LoadModule cache_module modules/mod_cache.so
# LoadModule disk_cache_module modules/mod_disk_cache.so

mod_cgi

Allows the execution of CGI scripts.

# LoadModule cgi_module modules/mod_cgi.so

mod_dav

Implements the WebDAV (Web-based Distributed Authoring and Versioning) funcionality.

# LoadModule dav_module modules/mod_dav.so
# LoadModule dav_fs_module modules/mod_dav_fs.so

mod_env

Controls the internal environment variables which are sent out to CGI scripts and SSI pages.

# LoadModule env_module modules/mod_env.so


Jul 20, 2009

Repositorio local de paquetes RPM por HTTP

Muchas veces puede ser necesario instalar en nuestra red un repositorio local de paquetes, ya que si por ejemplo se tienen muchas máquinas y surge una actualización, todos los equipos realizarán la misma operación (descargar la actualización de Internet) consumiendo ancho de banda para la empresa.

Otro de los motivos para instalar un repositorio local es la rapidez, ya que al encontrarse el repositorio dentro de la propia LAN, el proceso de descarga e instalación será mucho más rápido que si se trabaja sobre un servidor remoto.

Y por último, también se gana en seguridad, ya que sólo una de las máquinas (la que contenga el repositorio local) será la que tenga que tener acceso a Internet para descargar las actualizaciones, evitando de esta forma que el resto de equipos (susceptibles de instalar paquetes) tengan que salir a Internet.

Las pruebas se van a hacer en una CentOS 5.3, y para ello se va a crear un repositorio local para esta misma distribución de 64 bits, el cual será ofrecido al resto de máquinas de la LAN a través de un servidor Apache.

Lo primero que vamos a hacer es crear la estructura de directorios dentro del servidor que hará las labores de repositorio (centos01, con dirección IP 192.168.1.10).
[root@centos01 ~]# mkdir -p /var/www/mirror/CentOS/5.3/os/x86_64/CentOS

[root@centos01 ~]# mkdir -p /var/www/mirror/CentOS/5.3/updates/x86_64/RPMS

El directorio os lo utilizaremos para almacenar los paquetes base del sistema operativo, es decir, los que vienen nada más liberarse la distribución.

Si se tiene habilitado SELinux, habrá que modificar las listas de control de acceso (ACLs) de los contextos de seguridad del directorio raíz.
[root@centos01 ~]# chcon -R -u system_u /var/www/mirror/

[root@centos01 ~]# chcon -R -t httpd_sys_content_t /var/www/mirror/

Y a nivel de firewall, habrá que añadir una regla para abrir el puerto 80 (HTTP).
[root@centos01 ~]# cat /etc/sysconfig/iptables
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp --dport ssh -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp --dport http -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp -j ACCEPT
-A RH-Firewall-1-INPUT -j LOG
-A RH-Firewall-1-INPUT -j REJECT
COMMIT

El contenido del directorio os no cambiará nunca, así que lo que haremos será copiar en él los paquetes base desde un DVD.
[root@centos01 ~]# cp /media/CentOS_5.3_Final/CentOS/* /var/www/mirror/CentOS/5.3/os/x86_64/CentOS

Si se quiere comprobar la firma de los paquetes, ubicaremos la clave GPG en el directorio x86_64.
[root@centos01 ~]# ls /var/www/mirror/CentOS/5.3/os/x86_64/
RPM-GPG-KEY-CentOS-5 CentOS

A continuación tendremos que crear el directorio repodata asociado a dicho contenido base, el cual contendrá ficheros XML encargados de indexar los paquetes. Para ello necesitaremos tener instalado el paquete createrepo.
[root@centos01 ~]# yum install createrepo

[root@centos01 ~]# createrepo /var/www/mirror/CentOS/5.3/os/x86_64/

Las actualizaciones que vaya publicando CentOS las ubicaremos dentro del directorio updates. Este contenido deberá estar sincronizado con alguno de los repositorios de CentOS situados en Internet y que sean compatibles con rsync, ya que esta herramienta la utilizaremos para realizar dicha sincronización de forma periódica (definiremos una tarea en el cron para que se ejecute por ejemplo todos los días a la 01:05h - update_repo.sh).
[root@centos01 ~]# cat /etc/crontab
...
5 1 * * * /root/update_repo.sh

[root@centos01 ~]# cat /root/update_repo.sh
#!/bin/bash
rsync -at --delete rsync://mirrors.kernel.org/centos/5.3/updates/x86_64/RPMS/ /var/www/mirror/CentOS/5.3/updates/x86_64/RPMS/

if [ $(find /var/www/mirror/CentOS/5.3/updates/x86_64/RPMS/ -cmin -60 | wc -l) -gt 0 ]; then
createrepo /var/www/mirror/CentOS/5.3/updates/x86_64/
fi

[root@centos01 ~]# chmod +x /root/update_repo.sh

El script anterior lo que hace es sincronizar las actualizaciones disponibles para CentOS 5.3 en kernel.org, con nuestro directorio local, descargando únicamente los paquetes que hayan sido incorporados o modificados. A través de la línea if se comprobará si realmente ha habido alguna descarga, y en caso afirmativo, se volverá a generar nuevamente el directorio createrepo.

El siguiente paso será el de definir un virtual host para ofrecer ese contenido. También habrá que reiniciar Apache.
[root@centos01 ~]# cat /etc/httpd/conf.d/updates.conf
NameVirtualHost 192.168.1.10:80
<VirtualHost 192.168.1.10:80>
ServerName centos01
DocumentRoot /var/www/mirror
ErrorLog logs/updates-error_log
CustomLog logs/updates-acces_log combined
<Directory /var/www/mirror>
Options Indexes Includes
</Directory>
</VirtualHost>

[root@centos01 ~]# service httpd restart

Y ya por último, habrá que crear un fichero .repo en cada una de las máquinas que vayan a emplear el repositorio local. Para ello haremos una copia de un archivo ya existente (con el objetivo de salvaguardar los contextos de SELinux), lo borraremos y lo editaremos.
[root@centos02 ~]# cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Local.repo

[root@centos02 ~]# >/etc/yum.repos.d/CentOS-Local.repo

[root@centos02 ~]# vim /etc/yum.repos.d/CentOS-Local.repo
[base-local]
name=CentOS-$releasever - Base Local
baseurl=http://192.168.1.10/CentOS/5.3/os/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://192.168.1.10/CentOS/5.3/os/$basearch/RPM-GPG-KEY-CentOS-5

[update-local]
name=CentOS-$releasever - Updates Local
baseurl=http://192.168.1.10/CentOS/5.3/updates/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://192.168.1.10/CentOS/5.3/os/$basearch/RPM-GPG-KEY-CentOS-5