J'essaie de faire en sorte que Django télécharge des fichiers statiques sur S3, mais je reçois une erreur 403 interdite, et je ne sais pas pourquoi.
Full Stacktrace:
Traceback (most recent call last):
File "manage.py", line 14, in <module>
execute_manager(settings)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/core/management/__init__.py", line 438, in execute_manager
utility.execute()
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/core/management/__init__.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/core/management/base.py", line 191, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/core/management/base.py", line 220, in execute
output = self.handle(*args, **options)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/core/management/base.py", line 351, in handle
return self.handle_noargs(**options)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/contrib/staticfiles/management/commands/collectstatic.py", line 89, in handle_noargs
self.copy_file(path, prefixed_path, storage, **options)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/contrib/staticfiles/management/commands/collectstatic.py", line 184, in copy_file
if not self.delete_file(path, prefixed_path, source_storage, **options):
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/Django/contrib/staticfiles/management/commands/collectstatic.py", line 115, in delete_file
if self.storage.exists(prefixed_path):
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/storages/backends/s3boto.py", line 209, in exists
return k.exists()
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/boto/s3/key.py", line 391, in exists
return bool(self.bucket.lookup(self.name))
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/boto/s3/bucket.py", line 143, in lookup
return self.get_key(key_name, headers=headers)
File "/home/levi/Projects/DoneBox/.virtualenv/local/lib/python2.7/site-packages/boto/s3/bucket.py", line 208, in get_key
response.status, response.reason, '')
boto.exception.S3ResponseError: S3ResponseError: 403 Forbidden
Contenu de settings.py:
import os
DIRNAME = os.path.dirname(__file__)
# Django settings for DoneBox project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', '[email protected]'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'Django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'Oracle'.
'NAME': os.path.join(DIRNAME, "box.sqlite"), # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'Host': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Denver'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = "d1eyn4cjl5vzx0.cloudfront.net"
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = os.path.join(DIRNAME, "static")
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = "d280kzug7l5rug.cloudfront.net"
# URL prefix for admin static files -- CSS, JavaScript and images.
# Make sure to use a trailing slash.
# Examples: "http://foo.com/static/admin/", "/static/admin/".
ADMIN_MEDIA_PREFIX = '/static/admin/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/Django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.join(DIRNAME, "main", "static"),
)
# List of Finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'Django.contrib.staticfiles.finders.FileSystemFinder',
'Django.contrib.staticfiles.finders.AppDirectoriesFinder',
'Django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# Make this unique, and don't share it with anybody.
SECRET_KEY = '<snip>'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'Django.template.loaders.filesystem.Loader',
'Django.template.loaders.app_directories.Loader',
'Django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'Django.middleware.common.CommonMiddleware',
'Django.contrib.sessions.middleware.SessionMiddleware',
'Django.middleware.csrf.CsrfViewMiddleware',
'Django.contrib.auth.middleware.AuthenticationMiddleware',
'Django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'DoneBox.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/Django_templates" or "C:/www/Django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.join(DIRNAME, "main", "templates"),
os.path.join(DIRNAME, "templates"),
os.path.join(DIRNAME, "basic", "blog", "templates"),
)
INSTALLED_APPS = (
'Django.contrib.auth',
'Django.contrib.contenttypes',
'Django.contrib.sessions',
'Django.contrib.sites',
'Django.contrib.messages',
'Django.contrib.staticfiles',
'Django.contrib.sitemaps',
# Uncomment the next line to enable the admin:
'Django.contrib.admin',
# Uncomment the next line to enable admin documentation:
'storages',
'Django.contrib.admindocs',
'main',
'contacts',
'piston',
'registration',
# 'contact_form',
'basic',
'basic.blog',
)
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'Django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'Django.request': {
'handlers': ['mail_admins'],
'level': 'DEBUG',
'propagate': True,
},
'Django.db.backends': {
'handlers': ['mail_admins'],
'level': 'DEBUG',
'propagate': True,
}
}
}
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = '<snip>'
AWS_SECRET_ACCESS_KEY = '<snip>'
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_STORAGE_BUCKET_NAME = "donebox-static"
STATIC_FILES_BUCKET = "donebox-static"
MEDIA_FILES_BUCKET = "donebox-media"
ACCOUNT_ACTIVATION_DAYS = 7
EMAIL_Host = "email-smtp.us-east-1.amazonaws.com"
EMAIL_Host_USER = '<snip>'
EMAIL_Host_PASSWORD = '<snip>'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
TEMPLATE_CONTEXT_PROCESSORS = (
"Django.contrib.auth.context_processors.auth",
"Django.core.context_processors.debug",
"Django.core.context_processors.i18n",
"Django.core.context_processors.media",
"Django.core.context_processors.static",
"Django.contrib.messages.context_processors.messages",
"DoneBox.main.context_processors_PandC",
)
Contenu de requirements.pip:
Django==1.3
Django-storages==1.1.4
Django-registration==0.8
Django-piston==0.2.3
Django-tagging==0.3.1
Django-extensions==0.8
BeautifulSoup==3.2.1
boto==2.4.1
mysql-python==1.2.3
tweepy==1.9
feedparser==5.1.2
pycrypto==2.6
Une recherche Google pour cette exception ne révèle rien d'intéressant. Je soupçonne que j'ai mal configuré les choses, bien que je ne sois pas sûr. Quelqu'un peut-il m'indiquer la bonne direction? Merci pour votre temps et votre considération.
J'utilise Amazon IAM pour l'ID de clé et la clé d'accès spécifiques et vient de basculer dans le même code 403 interdit. Il s'avère que vous devez accorder des autorisations qui ciblent les deux la racine du compartiment et ses sous-objets:
{
"Statement": [
{
"Principal": {
"AWS": "*"
},
"Effect": "Allow",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::bucket-name/*", "arn:aws:s3:::bucket-name"]
}
]
}
Je vous recommande d'essayer de tester vos informations d'identification AWS séparément pour vérifier si les informations d'identification sont réellement autorisées à lire et à écrire des données dans le compartiment S3. Ce qui suit devrait fonctionner:
>>> import boto
>>> s3 = boto.connect_s3('<access_key>', '<secret_key>')
>>> bucket = s3.lookup('donebox-static')
>>> key = bucket.new_key('testkey')
>>> key.set_contents_from_string('This is a test')
>>> key.exists()
>>> key.delete()
Vous devriez essayer le même test avec l'autre compartiment ("donebox-media"). Si cela fonctionne, les autorisations sont correctes et le problème réside dans le code ou la configuration des stockages Django. Si cela échoue avec un 403, alors soit:
J'espère que ça aide. S'il vous plaît rapporter vos conclusions.
J'ai eu le même problème et j'ai finalement découvert que le vrai problème était SERVER TIME . Il était mal configuré et AWS répond par un message 403 FORBIDDEN.
En utilisant Debian, vous pouvez autoconfigurer en utilisant NTP:
ntpdate 0.pool.ntp.org
Cela se produira également si les paramètres horaires de votre machine sont incorrects.
Il est également possible que les informations d'identification incorrectes soient utilisées. Vérifier:
import boto
s3 = boto.connect_s3('<your access key>', '<your secret key>')
bucket = s3.get_bucket('<your bucket>') # does this work?
s3 = boto.connect_s3()
s3.aws_access_key_id # is the same key being used by default?
Sinon, jetez un coup d'œil à ~/.boto
, ~/.aws/config
et ~/.aws/credentials
.
Au cas où cela aiderait quelqu'un, j'ai dû ajouter l'entrée de configuration suivante pour que collectstatic
fonctionne et ne retourne pas 403:
AWS_DEFAULT_ACL = ''
Voici un raffinement avec des autorisations minimales . Dans tous les cas, comme indiqué ci-dessus, ailleurss3:ListAllMyBuckets
est nécessaire sur tous les compartiments.
Dans sa configuration par défaut, Django-storages téléchargera des fichiers sur S3 avec des autorisations de lecture publique - voir backend de Django-storages Amazon S3 } _
Des essais et des erreurs ont révélé que dans cette configuration par défaut, les deux seules autorisations requises sont s3:PutObject
pour télécharger un fichier à la première place et s3:PutObjectAcl
pour définir les autorisations de cet objet sur public.
Aucune action supplémentaire n'est requise car, à partir de ce moment, la lecture est désormais publique sur l'objet.
Stratégie d'utilisateur IAM - lecture publique (par défaut):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "arn:aws:s3:::*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::bucketname/*"
}
]
}
Il n’est pas toujours souhaitable d’avoir des objets lisibles en public. Ceci est réalisé en définissant la propriété correspondante dans le fichier de paramètres.
Django settings.py:
...
AWS_DEFAULT_ACL = "private"
...
Et puis le s3:PutObjectAcl
n'est plus requis et les autorisations minimales sont les suivantes:
Stratégie utilisateur IAM - private:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "arn:aws:s3:::*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::bucketname/*"
}
]
}
Une autre solution évitant les stratégies personnalisées et utilisant les stratégies prédéfinies AWS:
Ajoutez des autorisations d'accès complet S3 à votre utilisateur S3.
Peut-être que vous n'avez pas réellement accès au seau que vous essayez de rechercher/obtenir/créer ..
Rappelez-vous:Les noms de compartiment doivent être uniques sur l’ensemble du système S3eco. Par conséquent, si vous essayez d’accéder à (rechercher/obtenir/créer) un compartiment nommé «test», vous n’y aurez pas accès .