<h2>Entendendo Roles: A Estrutura Profissional do Ansible</h2>
<p>Uma role no Ansible é um padrão de organização que encapsula lógica de configuração de forma reutilizável e modular. Diferentemente de playbooks lineares, roles oferecem uma estrutura de diretórios padronizada que facilita a manutenção, o versionamento e o compartilhamento de código entre projetos. Quando você trabalha em ambientes corporativos, a diferença entre um playbook monolítico e uma estrutura baseada em roles é a diferença entre caos e profissionalismo.</p>
<p>Uma role segue convenções de diretórios. Ansible procura automaticamente por arquivos em locais específicos: <code>tasks/</code> para tarefas, <code>handlers/</code> para notificações, <code>templates/</code> para arquivos Jinja2, <code>vars/</code> para variáveis privadas e <code>defaults/</code> para valores padrão. Você também encontrará <code>files/</code> para arquivos estáticos, <code>meta/</code> para dependências e <code>tests/</code> para validação.</p>
<pre><code>minha_aplicacao/
├── defaults/
│ └── main.yml
├── files/
│ └── aplicacao.conf
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/
└── main.yml</code></pre>
<h3>Criando sua primeira role</h3>
<p>Para começar, use o comando <code>ansible-galaxy init nome_da_role</code>. Isso gera a estrutura completa automaticamente. Vamos criar uma role para instalar e configurar Nginx:</p>
<pre><code class="language-bash">ansible-galaxy init webserver</code></pre>
<p>Dentro de <code>webserver/tasks/main.yml</code>, adicione:</p>
<pre><code class="language-yaml">---
- name: Instalar Nginx
apt:
name: nginx
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: Ativar Nginx
systemd:
name: nginx
enabled: yes
state: started
- name: Copiar configuração Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
backup: yes
notify: restart nginx
- name: Validar sintaxe Nginx
command: nginx -t
changed_when: false</code></pre>
<p>Em <code>webserver/defaults/main.yml</code>, defina valores padrão:</p>
<pre><code class="language-yaml">---
nginx_port: 80
nginx_user: www-data
nginx_worker_processes: auto
nginx_keepalive_timeout: 65
max_body_size: 20m</code></pre>
<p>Em <code>webserver/vars/main.yml</code>, adicione variáveis que sobrescrevem defaults:</p>
<pre><code class="language-yaml">---
nginx_conf_path: /etc/nginx/sites-available/default
nginx_service_name: nginx</code></pre>
<p>Em <code>webserver/handlers/main.yml</code>, defina ações acionadas por notificações:</p>
<pre><code class="language-yaml">---
- name: restart nginx
systemd:
name: nginx
state: restarted
- name: reload nginx
systemd:
name: nginx
state: reloaded</code></pre>
<h3>Usando roles em playbooks</h3>
<p>Para usar a role, crie um playbook <code>site.yml</code>:</p>
<pre><code class="language-yaml">---
- hosts: webservers
become: yes
roles:
- webserver</code></pre>
<p>Ou com variáveis inline:</p>
<pre><code class="language-yaml">---
- hosts: webservers
become: yes
roles:
- role: webserver
vars:
nginx_port: 8080
max_body_size: 50m</code></pre>
<p>Você também pode passar argumentos condicionalmente:</p>
<pre><code class="language-yaml">---
- hosts: all
roles:
- role: webserver
when: inventory_hostname in groups['webservers']
tags:
- web
- setup</code></pre>
<h2>Templates Jinja2: Dinamismo em Configurações</h2>
<p>Jinja2 é um motor de templates poderoso que permite gerar arquivos de configuração dinamicamente usando variáveis do Ansible. Em vez de manter múltiplas versões estáticas de um arquivo de configuração, você cria um template que se adapta ao contexto de cada host. Isso reduz drasticamente duplicação e erros humanos em ambientes heterogêneos.</p>
<p>A sintaxe Jinja2 usa <code>{{ variavel }}</code> para inserção de variáveis, <code>{% if condicao %}</code> para lógica condicional e <code>{% for item in lista %}</code> para loops. Dentro de um template, você tem acesso a todas as variáveis do Ansible (facts, vars, defaults) e pode aplicar filtros para transformar dados.</p>
<h3>Estrutura básica de templates</h3>
<p>Crie <code>webserver/templates/nginx.conf.j2</code>:</p>
<pre><code class="language-nginx">user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
pid /run/nginx.pid;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout {{ nginx_keepalive_timeout }};
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss;
include /etc/nginx/sites-enabled/*;
}</code></pre>
<h3>Lógica condicional em templates</h3>
<p>Para adicionar blocos opcionais baseado em variáveis, edite o template:</p>
<pre><code class="language-nginx">http {
{% if enable_ssl %}
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
{% endif %}
{% if enable_compression %}
gzip on;
gzip_types text/plain text/css application/json application/javascript;
{% endif %}
{% if custom_headers %}
add_header X-Custom-Header "{{ custom_header_value }}";
{% endif %}
}</code></pre>
<p>Em seu <code>defaults/main.yml</code>:</p>
<pre><code class="language-yaml">enable_ssl: false
enable_compression: true
custom_headers: false</code></pre>
<h3>Loops em templates</h3>
<p>Para gerar múltiplos blocos de configuração, use loops. Crie <code>webserver/templates/vhosts.conf.j2</code>:</p>
<pre><code class="language-nginx">{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.port | default(80) }};
server_name {{ vhost.server_name }};
root {{ vhost.root | default('/var/www/html') }}; index {{ vhost.index | default('index.html') }};
{% if vhost.ssl_enabled | default(false) %}
listen 443 ssl;
ssl_certificate {{ vhost.ssl_cert }};
ssl_certificate_key {{ vhost.ssl_key }};
{% endif %}
location / {
try_files $uri $uri/ =404;
}
{% if vhost.proxy_pass %}
location /api {
proxy_pass {{ vhost.proxy_pass }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
{% endif %}
}
{% endfor %}</code></pre>
<p>Defina em <code>vars/main.yml</code>:</p>
<pre><code class="language-yaml">nginx_vhosts:
- server_name: "exemplo.com"
port: 80
root: "/var/www/exemplo"
proxy_pass: "http://localhost:3000"
- server_name: "api.exemplo.com"
port: 80
root: "/var/www/api"
ssl_enabled: true
ssl_cert: "/etc/ssl/certs/api.crt"
ssl_key: "/etc/ssl/private/api.key"</code></pre>
<h3>Filtros Jinja2 essenciais</h3>
<p>Jinja2 oferece filtros que transformam dados. Alguns dos mais úteis no contexto Ansible:</p>
<pre><code class="language-jinja2">{{ variavel | default('valor_padrao') }} {{ lista | join(', ') }} {{ string | upper }} {{ string | lower }} {{ numero | string }} {{ dados | to_nice_json }} {{ caminho | basename }} {{ string | regex_replace('^(.)$', 'prefixo_\\1') }} {{ lista | select('match', 'padrao.') | list }}</code></pre>
<p>Um exemplo prático no template:</p>
<pre><code class="language-nginx"># Comentário gerado em {{ ansible_date_time.iso8601 }}
Host: {{ inventory_hostname }}
OS: {{ ansible_distribution }} {{ ansible_distribution_version }}
error_log /var/log/nginx/error.log {{ log_level | default('warn') }};
access_log /var/log/nginx/access.log {% if access_log_format %}{{ access_log_format }}{% else %}combined{% endif %};</code></pre>
<h2>Ansible Vault: Segurança para Dados Sensíveis</h2>
<p>Ansible Vault é um sistema de criptografia que protege arquivos contendo informações sensíveis como senhas, chaves privadas e tokens de API. Toda organização que trabalha com configuração como código deve usar Vault; armazenar senhas em texto plano em repositórios Git é uma vulnerabilidade grave. O Vault usa criptografia AES-256 e requer uma senha para descriptografar arquivos durante a execução do playbook.</p>
<p>A estratégia é simples: você cria um arquivo Vault contendo valores sensíveis, referencia esses valores em seus playbooks e templates normalmente, e o Ansible descriptografa automaticamente quando necessário. Isso mantém o fluxo de trabalho transparente enquanto protege dados em repouso.</p>
<h3>Criando e editando arquivos Vault</h3>
<p>Para criar um novo arquivo criptografado:</p>
<pre><code class="language-bash">ansible-vault create credenciais.yml</code></pre>
<p>Você será solicitado a definir uma senha. Então um editor abre para você adicionar conteúdo:</p>
<pre><code class="language-yaml">---
db_password: "senhaForte123!@#"
api_key: "sk-proj-1a2b3c4d5e6f7g8h9i0j"
jwt_secret: "seu-jwt-secret-muito-longo-aqui"
backup_passphrase: "backup@2024"</code></pre>
<p>Para editar depois:</p>
<pre><code class="language-bash">ansible-vault edit credenciais.yml</code></pre>
<p>Para visualizar sem editar:</p>
<pre><code class="language-bash">ansible-vault view credenciais.yml</code></pre>
<p>Para mudar a senha:</p>
<pre><code class="language-bash">ansible-vault rekey credenciais.yml</code></pre>
<h3>Integrando Vault em playbooks</h3>
<p>Inclua o arquivo Vault em seu playbook referenciando-o normalmente:</p>
<pre><code class="language-yaml">---
- hosts: database_servers
become: yes
vars_files:
- credenciais.yml
tasks:
- name: Configurar PostgreSQL
postgresql_query:
db: postgres
query: "ALTER USER postgres WITH PASSWORD '{{ db_password }}';"
environment:
PGPASSWORD: "{{ db_password }}"
- name: Gerar arquivo de configuração da aplicação
template:
src: app_config.yml.j2
dest: /etc/app/config.yml
mode: '0640'
owner: app_user
group: app_group
- name: Registrar API key no serviço
uri:
url: "https://api.exemplo.com/register"
method: POST
body_format: json
body:
api_key: "{{ api_key }}"
environment: "production"</code></pre>
<p>Em <code>templates/app_config.yml.j2</code>:</p>
<pre><code class="language-yaml"># Configuração gerada automaticamente - não editar manualmente
database:
host: {{ db_host }}
port: {{ db_port }}
username: {{ db_user }}
password: {{ db_password }}
name: {{ db_name }}
api:
endpoint: {{ api_endpoint }}
key: {{ api_key }}
timeout: 30
backup:
enabled: true
passphrase: {{ backup_passphrase }}
retention_days: 30</code></pre>
<h3>Executando playbooks com Vault</h3>
<p>Para executar um playbook que use arquivos Vault, use a flag <code>--ask-vault-pass</code>:</p>
<pre><code class="language-bash">ansible-playbook site.yml --ask-vault-pass</code></pre>
<p>O Ansible solicitará a senha do Vault. Alternativamente, armazene a senha em um arquivo seguro:</p>
<pre><code class="language-bash"># Crie um arquivo com a senha (tenha cuidado com permissões)
echo "minha-senha-vault" > ~/.vault_password
Configure permissões restritivas
chmod 600 ~/.vault_password
Execute o playbook
ansible-playbook site.yml --vault-password-file ~/.vault_password</code></pre>
<p>Ou configure no arquivo <code>ansible.cfg</code>:</p>
<pre><code class="language-ini">[defaults]
vault_password_file = ~/.vault_password</code></pre>
<h3>Criptografando valores individuais</h3>
<p>Você não precisa criptografar arquivos inteiros. Use <code>ansible-vault encrypt_string</code> para criptografar um valor específico:</p>
<pre><code class="language-bash">ansible-vault encrypt_string 'senhaForte123!@#' --name 'db_password'</code></pre>
<p>Saída:</p>
<pre><code class="language-yaml">db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
32643062306465613666336661666565356165303063666165653132613734623634303834306537
3237353461303061623162343739336666653535666234650a343438333436643631663539383639
31313665633439643363396164313364316437353235383164633761616465616266613264633736
3231656139386234300a346334396632393134626634643461363632616238346264653064383862
6266</code></pre>
<p>Copie e cole esse bloco em seus arquivos YAML:</p>
<pre><code class="language-yaml">---
- hosts: all
vars:
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
32643062306465613666336661666565356165303063666165653132613734623634303834306537
3237353461303061623162343739336666653535666234650a343438333436643631663539383639
31313665633439643363396164313364316437353235383164633761616465616266613264633736
3231656139386234300a346334396632393134626634643461363632616238346264653064383862
6266
tasks:
- name: Usar senha descriptografada
debug:
msg: "Senha é {{ db_password }}"</code></pre>
<h3>Gerenciamento de segurança com Vault</h3>
<p>Para manter segurança em equipes, nunca commite o arquivo <code>.vault_password</code> no Git. Use um <code>.gitignore</code>:</p>
<pre><code>.vault_password
*.vault
*.key</code></pre>
<p>Para compartilhar a senha com colegas de trabalho, use um gerenciador de senhas corporativo ou passe de forma segura fora do repositório. Em ambientes de CI/CD, injete a senha como variável de ambiente:</p>
<pre><code class="language-bash">export ANSIBLE_VAULT_PASSWORD_FILE=/run/secrets/vault_password
ansible-playbook site.yml</code></pre>
<p>Em GitHub Actions:</p>
<pre><code class="language-yaml">- name: Run Ansible playbook
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: |
echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
chmod 600 /tmp/vault_pass
ansible-playbook site.yml --vault-password-file /tmp/vault_pass
rm /tmp/vault_pass</code></pre>
<h2>Integrando Roles, Templates e Vault em um Projeto Real</h2>
<p>A verdadeira potência emerge quando combinamos esses três componentes. Vamos construir um cenário realista: implantar uma aplicação Node.js com Nginx como proxy reverso, usando uma role bem estruturada, templates dinâmicos e dados sensíveis protegidos.</p>
<p>Estrutura do projeto:</p>
<pre><code>ansible-projeto/
├── ansible.cfg
├── inventario.yml
├── site.yml
├── credenciais.yml (criptografado com Vault)
├── roles/
│ ├── nodejs-app/
│ │ ├── defaults/main.yml
│ │ ├── tasks/main.yml
│ │ ├── templates/
│ │ │ ├── app.env.j2
│ │ │ └── systemd-app.service.j2
│ │ ├── handlers/main.yml
│ │ └── vars/main.yml
│ └── nginx-proxy/
│ ├── defaults/main.yml
│ ├── tasks/main.yml
│ ├── templates/
│ │ └── nginx-app.conf.j2
│ ├── handlers/main.yml
│ └── vars/main.yml
└── group_vars/
└── app_servers.yml</code></pre>
<p>Arquivo <code>ansible.cfg</code>:</p>
<pre><code class="language-ini">[defaults]
inventory = inventario.yml
vault_password_file = ~/.vault_password
roles_path = ./roles
host_key_checking = False</code></pre>
<p>Arquivo <code>inventario.yml</code>:</p>
<pre><code class="language-yaml">---
all:
children:
app_servers:
hosts:
app01.exemplo.com:
ansible_user: deploy
app02.exemplo.com:
ansible_user: deploy</code></pre>
<p>Arquivo <code>credenciais.yml</code> (criptografado):</p>
<pre><code class="language-yaml">---
db_host: postgres.interno.com
db_user: app_user
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
...conteudo_criptografado...
app_secret_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
...conteudo_criptografado...</code></pre>
<p>Arquivo <code>group_vars/app_servers.yml</code>:</p>
<pre><code class="language-yaml">---
app_name: minha-app
app_user: app
app_group: app
app_port: 3000
app_version: 1.2.3
nodejs_version: 18
nginx_proxy_port: 80</code></pre>
<p>Arquivo <code>site.yml</code>:</p>
<pre><code class="language-yaml">---
- hosts: app_servers
become: yes
vars_files:
- credenciais.yml
pre_tasks:
- name: Atualizar cache do apt
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
roles:
- nodejs-app
- nginx-proxy
post_tasks:
- name: Validar status da aplicação
uri:
url: "http://localhost/health"
method: GET
status_code: 200
register: health_check
retries: 3
delay: 5
until: health_check is success</code></pre>
<p>Role <code>nodejs-app</code> - <code>roles/nodejs-app/tasks/main.yml</code>:</p>
<pre><code class="language-yaml">---
- name: Instalar Node.js
block:
- name: Adicionar NodeSource repository
shell: curl -fsSL https://deb.nodesource.com/setup_{{ nodejs_version }}.x | sudo -E bash -
args:
warn: false
- name: Instalar Node.js
apt:
name: nodejs
state: present
- name: Criar usuário da aplicação
user:
name: "{{ app_user }}"
shell: /bin/bash
home: "/home/{{ app_user }}"
createhome: yes
state: present
- name: Clonar repositório da aplicação
git:
repo: "{{ app_repo_url }}"
dest: "/var/www/{{ app_name }}"
version: "{{ app_version }}"
update: yes
register: app_clone
become_user: "{{ app_user }}"
- name: Instalar dependências Node.js
npm:
path: "/var/www/{{ app_name }}"
state: present
when: app_clone is changed
- name: Gerar arquivo .env
template:
src: app.env.j2
dest: "/var/www/{{ app_name }}/.env"
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: '0640'
notify: restart app
- name: Criar serviço systemd
template:
src: systemd-app.service.j2
dest: "/etc/systemd/system/{{ app_name }}.service"
owner: root
group: root
mode: '0644'
notify: restart app
- name: Habilitar e iniciar serviço
systemd:
name: "{{ app_name }}"
enabled: yes
state: started
daemon_reload: yes</code></pre>
<p>Template <code>roles/nodejs-app/templates/app.env.j2</code>:</p>
<pre><code class="language-env"># Arquivo de configuração gerado automaticamente
Última atualização: {{ ansible_date_time.iso8601 }}
NODE_ENV=production
APP_PORT={{ app_port }}
APP_NAME={{ app_name }}
APP_VERSION={{ app_version }}
Database
DB_HOST={{ db_host }}
DB_USER={{ db_user }}
DB_PASSWORD={{ db_password }}
DB_NAME={{ app_name }}_prod
Security
SECRET_KEY={{ app_secret_key }}
SESSION_SECRET={{ app_session_secret | default('change-me') }}
Features
ENABLE_CACHE={{ enable_cache | default('true') }} ENABLE_LOGGING={{ enable_logging | default('true') }} LOG_LEVEL={{ log_level | default('info') }}</code></pre>
<p>Template <code>roles/nodejs-app/templates/systemd-app.service.j2</code>:</p>
<pre><code class="language-ini">[Unit]
Description={{ app_name }} Node.js Application
After=network.target
[Service]
Type=simple
User={{ app_user }}
Group={{ app_group }}
WorkingDirectory=/var/www/{{ app_name }}
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
Environment="NODE_ENV=production"
Environment="PORT={{ app_port }}"
[Install]
WantedBy=multi-user.target</code></pre>
<p>Role <code>nginx-proxy</code> - <code>roles/nginx-proxy/tasks/main.yml</code>:</p>
<pre><code class="language-yaml">---
- name: Instalar Nginx
apt:
name: nginx
state: present
- name: Gerar configuração Nginx
template:
src: nginx-app.conf.j2
dest: "/etc/nginx/sites-available/{{ app_name }}"
owner: root
group: root
mode: '0644'
notify: test and reload nginx
- name: Ativar site Nginx
file:
src: "/etc/nginx/sites-available/{{ app_name }}"
dest: "/etc/nginx/sites-enabled/{{ app_name }}"
state: link
notify: test and reload nginx
- name: Habilitar e iniciar Nginx
systemd:
name: nginx
enabled: yes
state: started</code></pre>
<p>Template <code>roles/nginx-proxy/templates/nginx-app.conf.j2</code>:</p>
<pre><code class="language-nginx"># Configuração Nginx para {{ app_name }}
Gerada em {{ ansible_date_time.iso8601 }} em {{ inventory_hostname }}
upstream {{ app_name }}_backend {
server 127.0.0.1:{{ app_port }};
keepalive 32;
}
server {
listen {{ nginx_proxy_port }};
server_name {{ server_names | join(' ') }};
access_log /var/log/nginx/{{ app_name }}_access.log combined;
error_log /var/log/nginx/{{ app_name }}_error.log warn;
client_max_body_size 50m;
Health check endpoint
location /health {
access_log off;
proxy_pass http://{{ app_name }}_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
API e aplicação
location / {
proxy_pass http://{{ app_name }}_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
{% if enable_gzip | default(true) %}
gzip on;
gzip_types text/plain text/css text/javascript application/json application/javascript;
gzip_min_length 1000;
{% endif %}
}</code></pre>
<p>Para executar:</p>
<pre><code class="language-bash"># Primeira execução - solicita senha do Vault
ansible-playbook site.yml --ask-vault-pass
Com arquivo de senha (mais seguro em CI/CD)
ansible-playbook site.yml --vault-password-file ~/.vault_password</code></pre>
<h2>Conclusão</h2>
<p>Dominar Roles, Templates Jinja2 e Ansible Vault transforma você de um usuário básico de Ansible para um profissional capaz de implementar infraestrutura como código em escala corporativa. As três competências trabalham juntas: Roles organizam sua lógica em estruturas reutilizáveis; Templates Jinja2 tornam configurações dinâmicas e adaptáveis; Vault protege dados sensíveis mantendo o fluxo transparente. Esse tripé é a base para automação confiável, auditável e segura.</p>
<p>Na prática, sempre pense em reutilização: uma role bem escrita deve funcionar em múltiplos contextos através de variáveis. Use templates para tudo que varia entre ambientes—nunca commite arquivos de configuração estáticos quando um template pode substituí-lo. E nunca, em hipótese alguma, commite senhas em repositórios; o Vault existe justamente para isso e seu custo de implementação é praticamente zero.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html" target="_blank" rel="noopener noreferrer">Ansible Roles - Documentação Oficial</a></li>
<li><a href="https://jinja.palletsprojects.com/" target="_blank" rel="noopener noreferrer">Jinja2 Template Engine - Documentação</a></li>
<li><a href="https://docs.ansible.com/ansible/latest/user_guide/vault.html" target="_blank" rel="noopener noreferrer">Ansible Vault - Protecting Sensitive Data</a></li>
<li><a href="https://galaxy.ansible.com/" target="_blank" rel="noopener noreferrer">Ansible Galaxy - Community Roles</a></li>
<li><a href="https://www.oreilly.com/library/view/infrastructure-as-code/9781491924334/" target="_blank" rel="noopener noreferrer">DevOps and Infrastructure as Code - Book by Kief Morris</a></li>
</ul>
<p><!-- FIM --></p>