org.apache.hadoop.security.AccessControlException: в доступе отказано при попытке доступа к корзине S3 через URI s3n с помощью API-интерфейсов Hadoop Java на EC2
сценарий
Я создаю роль AWS IAM под названием "my-role", определяющую EC2 в качестве доверенного объекта, то есть используя документ политики доверительных отношений:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Роль имеет следующую политику:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetBucketAcl",
"s3:GetBucketCORS",
"s3:GetBucketLocation",
"s3:GetBucketLogging",
"s3:GetBucketNotification",
"s3:GetBucketPolicy",
"s3:GetBucketRequestPayment",
"s3:GetBucketTagging",
"s3:GetBucketVersioning",
"s3:GetBucketWebsite",
"s3:GetLifecycleConfiguration",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectTorrent",
"s3:GetObjectVersion",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTorrent",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListBucketVersions",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:PutObjectAcl",
"s3:PutObjectVersionAcl",
"s3:RestoreObject"
],
"Resource": [
"arn:aws:s3:::my-bucket/*"
]
}
]
}
Я запускаю экземпляр EC2 (Amazon Linux 2014.09.1) из командной строки, используя AWS CLI, указывая "my-role" в качестве профиля экземпляра, и все работает нормально. Я проверяю, что экземпляр эффективно принимает "мою роль", выполнив:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
запросить, например, метаданные, из которых я получаю ответmy-role
;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/my-role
из которого я получаю временные учетные данные, связанные с "моей ролью".
Примером такого ответа для получения учетных данных является что-то вроде:
{
"Code" : "Success",
"LastUpdated" : "2015-01-19T10:37:35Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "an-access-key-id",
"SecretAccessKey" : "a-secret-access-key",
"Token" : "a-token",
"Expiration" : "2015-01-19T16:47:09Z"
}
aws s3 ls s3://my-bucket/
из которого я правильно получаю список, содержащий первый подкаталог (-ы) в разделе "my-bucket". (CLI-интерфейс AWS устанавливается и настраивается по умолчанию при запуске этого AMI. Экземпляр EC2 и корзина S3 находятся в одной учетной записи AWS)
Я запускаю / устанавливаю сервер и контейнер Tomcat7 в таком экземпляре, на котором я без проблем разворачиваю сервлет J2EE 1.7.
Такой сервлет должен загружать в локальную файловую систему файл из корзины S3, в частности из s3://my-bucket/custom-path/file.tar.gz
используя Hadoop Java API. (Пожалуйста, обратите внимание, что я попробовал артефакт hadoop-common 2.4.x, 2.5.x, 2.6.x без каких-либо положительных результатов. Я опубликую ниже исключения, которое получаю при использовании 2.5.x)
В сервлете я получаю свежие учетные данные из URL-адреса метаданных экземпляра, упомянутого выше, и использую их для настройки моего экземпляра Hadoop Java API:
...
Path path = new Path("s3n://my-bucket/");
Configuration conf = new Configuration();
conf.set("fs.defaultFS", path.toString());
conf.set("fs.s3n.awsAccessKeyId", myAwsAccessKeyId);
conf.set("fs.s3n.awsSecretAccessKey", myAwsSecretAccessKey);
conf.set("fs.s3n.awsSessionToken", mySessionToken);
...
Очевидно, что myAwsAccessKeyId
, myAwsSecretAccessKey
, а также mySessionToken
переменные Java, которые я предварительно установил с фактическими значениями. Затем я эффективно получаю экземпляр FileSystem, используя:
FileSystem fs = path.getFileSystem(conf);
Я могу получить всю конфигурацию, связанную с файловой системой (fs.getconf(). Get(key-name)) и убедиться, что все настроено так, как предполагалось.
проблема
Я не могу скачать s3://my-bucket/custom-path/file.tar.gz
с помощью:
...
fs.copyToLocalFile(false, new Path(path.toString()+"custom-path/file.tar.gz"), outputLocalPath);
...
Если я использую hadoop-common 2.5.x, я получаю IOException
:
org.apache.hadoop.security.AccessControlException: в доступе отказано: s3n://my-bucket/custom-path/file.tar.gz at org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.processException(Jets3tNativeFileSystem44torej.jpg) в org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.processException(Jets3tNativeFileSystemStore.java:427) в org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.handle.Ex.jj.Slay.HaseFid fs.s3native. DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke(Method.java:606) в org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.joopgap.ap): 7).io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102) в org.apache.hadoop.fs.s3native.$Proxy12.retrieveMetadata(Неизвестный источник) в org.apache.hadoop.fs.s3native.NativeS3FileSystem.getFileStatus:4). в org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:337) в org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:289) в org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1968) в org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1937) ...
Если я использую hadoop-common 2.4.x, я получаю NullPointerException
:
java.lang.NullPointerException в org.apache.hadoop.fs.s3native.NativeS3FileSystem.getFileStatus(NativeS3FileSystem.java:433) в org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:337) в org.ap. hadoop.fs.FileUtil.copy (FileUtil.java:289) в org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1968) в org.apache.hadoop.fs.FileSystem.copyToLocalFile (FileSystem.java: 1937)...
Просто для записей, если не установить учетные данные AWS, я получаю:
Идентификатор ключа доступа AWS и секретный ключ доступа должны быть указаны как имя пользователя или пароль (соответственно) URL-адреса s3n или путем установки свойств fs.s3n.awsAccess KeyId или fs.s3n.awsSecretAccess Key (соответственно).
Финальные заметки
- Если я пытаюсь загрузить файл с того же URI (но s3 вместо s3n), используя команды CLI AWS из экземпляра, у меня НЕТ ПРОБЛЕМ.
- Если я попытаюсь загрузить дистрибутив Hadoop (например, 2.4.1 с https://archive.apache.org/dist/hadoop/core/hadoop-2.4.1/), разархивируйте его, извлеките временные учетные данные AWS из метаданных экземпляра. URL и попробуйте запустить
<hadoop-dir>/bin/hadoop fs -cp s3n://<aws-access-key-id>:<aws-secret-access-key>@my-bucket/custom-path/file.tar.gz .
Я снова получаю NPE:
Неустранимая внутренняя ошибка java.lang.NullPointerException в org.apache.hadoop.fs.s3native.NativeS3FileSystem.listStatus(NativeS3FileSystem.java:479) в org.apache.hadoop.fs.shell.PathData.getDirectoryContents(PathD68.java) в org.apache.hadoop.fs.shell.Command.recursePath(Command.java:347) в org.apache.hadoop.fs.shell.Ls.processPathArgument(Ls.java:96) в org.apache.hadoop.fs.shell.Command.processArgument(Command.java:260) в org.apache.hadoop.fs.shell.Command.processArguments(Command.java:244) в org.apache.hadoop.fs.shell.Command.processRawArguments(Command.java:190) в org.apache.hadoop.fs.shell.Command.run(Command.java:154) в org.apache.hadoop.fs.FsShell.run(FsShell.java:255) в org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70) в org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:84) в org.apache.hadoop.fs.FsShell.main(FsShell.java:308)
Извините за длинный пост, я просто старался быть как можно более подробным. Спасибо за любую возможную помощь здесь.
1 ответ
Вы используете STS/ временные учетные данные AWS; в настоящее время они не поддерживаются s3
или же s3n
FileSystem
реализации в Hadoop.
AWS STS/ временные учетные данные включают в себя не только (ключ доступа, секретный ключ), но и дополнительно токен сеанса. Хадуп s3
а также s3n
FileSystem
(s) пока не поддерживают включение токена сеанса (т.е. ваша конфигурация fs.s3n.awsSessionToken
не поддерживается и игнорируется s3n
FileSystem
,
Из AmazonS3 - Hadoop Wiki...
(Обратите внимание, что нет упоминания о fs.s3.awsSessionToken
):
Настройка для использования файловых систем s3/ s3n
Отредактируйте свой
core-site.xml
файл для включения ваших ключей S3<property> <name>fs.s3.awsAccessKeyId</name> <value>ID</value> </property> <property> <name>fs.s3.awsSecretAccessKey</name> <value>SECRET</value> </property>
Если вы посмотрите на S3Credentials.java из apache / hadoop на github.com, вы заметите, что понятие токена сеанса полностью отсутствует в представлении учетных данных S3.
Был представлен патч для устранения этого ограничения (подробно здесь); однако, это не было интегрировано.
Если вы используете роли экземпляра AWS IAM, вы можете изучить новые
s3a
FileSystem
это было добавлено в Hadoop 2.6.0. В нем утверждается, что он поддерживает аутентификацию на основе ролей IAM (то есть вам вообще не нужно явно указывать ключи).Билет Hadoop JIRA описывает, как настроить s3a
FileSystem
:
С https://issues.apache.org/jira/browse/HADOOP-10400:
fs.s3a.access.key
- Ваш идентификатор ключа доступа AWS (не указан для аутентификации роли)fs.s3a.secret.key
- Ваш секретный ключ AWS (не указан для аутентификации роли)