Notice
Recent Posts
Recent Comments
Link
투케이2K
1034. (Android/Java) AWS WebRTC Signaling 메시지를 주고 받기 위한 WebSocket 웹소켓 URL 생성 API AWS4Signer 헤더 생성 방법 본문
Android
1034. (Android/Java) AWS WebRTC Signaling 메시지를 주고 받기 위한 WebSocket 웹소켓 URL 생성 API AWS4Signer 헤더 생성 방법
투케이2K 2025. 10. 11. 11:37728x90
[개발 환경 설정]
개발 툴 : AndroidStudio
개발 언어 : Java / Kotlin

[소스 코드]
// --------------------------------------------------------------------------------------
[개발 및 테스트 환경]
// --------------------------------------------------------------------------------------
- 언어 : Java / Kotlin
- 개발 툴 : AndroidStudio
- 기술 구분 : AWS / AWS4Signer / WebRTC
- 사전) AWS 의존성 부여 설정
// --------------------------------------------
// [Aws build.gradle 라이브러리 정의] : targetSdk 33 ~ 34
// --------------------------------------------
/**
* implementation 'com.amazonaws:aws-android-sdk-kms:2.57.0'
* implementation 'com.amazonaws:aws-android-sdk-s3:2.57.0'
* implementation 'com.amazonaws:aws-android-sdk-iot:2.57.0'
* implementation 'com.amazonaws:aws-android-sdk-mobile-client:2.57.0'
* implementation 'com.amazonaws:aws-android-sdk-kinesisvideo:2.57.0'
* */
- 사전) AWS4Signer 설명 :
>> AWS SigV4 는 AWS API 요청에 인증 정보를 추가하기 위한 AWS 서명 프로토콜입니다
>> AWS SigV4 는 HTTP Authorization 헤더에서 또는 URL의 쿼리 문자열로 표현될 수 있습니다
>> AWS SigV4 요청에 서명하는 이유 :
- 요청자의 ID 확인 : 인증된 요청에는 액세스 키(액세스 키 ID, 비밀 액세스 키)를 사용하여 만든 서명이 필요합니다
- 전송 중인 데이터 보호 : 요청이 전송되는 동안 훼손되는 것을 방지하기 위해 일부 요청 요소를 사용하여 요청의 해시(다이제스트)를 계산하고 결과 해시 값을 요청의 일부로 포함합니다
- 잠재적 재생 공격으로부터 보호 : 대부분의 경우 요청서의 타임스탬프 시간으로부터 5분 이내에 AWS에 요청이 도착해야 합니다 (그렇지 않으면 AWS가 요청을 거부합니다)
>> AWS SigV4 서명 요청 프로세스 :
- 요청 세부 정보를 기반으로 표준 요청 생성
- AWS 자격 증명을 사용하여 서명 계산
- 이 서명을 요청에 Authorization 헤더로 추가
- 사전) WebRTC getSignalingChannelEndpoint HTTPS, WSS 사용 범위 설명 :
>> kinesisVideoClient.getSignalingChannelEndpoint 메서드는 Amazon Kinesis Video Streams with WebRTC 를 사용할 때, 시그널링 채널의 엔드포인트 주소를 가져오기 위해 사용됩니다.
>> 반환되는 주소들은 주로 시그널링 통신 (WebRTC peer 연결 설정을 위한 통신) 에 사용됩니다.
>> getSignalingChannelEndpoint 를 호출 하면 HTTP(S) 및 WSS(WebSocket Secure) 프로토콜을 사용하는 엔드포인트 주소들이 반환 됩니다.
>> getSignalingChannelEndpoint 호출 시 반환 되는 형식 예시 :
{
"ResourceEndpointList": [
{
"Protocol": "HTTPS",
"ResourceEndpoint": "https://<endpoint>"
},
{
"Protocol": "WSS",
"ResourceEndpoint": "wss://<endpoint>"
}
]
}
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[소스 코드]
// --------------------------------------------------------------------------------------
// --------------------------------------------
// [필요 변수 선언]
// --------------------------------------------
String ACCESS_KEY = "AK...LM"; // IAM 계정 AccessKey
String SECRET_KEY = "mn...si"; // IAM 계정 SecretKey
String REGION = "ap-northeast-1"; // AWS 리전 정보
String WSS_ENDPOINT = "WSS:// ...."; // WSS 엔드포인트
String CHANNEL_NAME = "DEVICE_1"; // 신호채널 명칭
String CLIENT_ID = "TEST_CLIENT"; // 접속 시도 클라이언트 고유 아이디 값
// --------------------------------------------
// [AWSCredentials 자격 증명 수행]
// --------------------------------------------
AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY); // TODO [IAM 계정 Key 초기화]
//BasicSessionCredentials credentials = new BasicSessionCredentials(ACCESS_KEY, SECRET_KEY, SESSION_TOKEN); // TODO [STS 임시 정보 초기화]
// --------------------------------------------
// [AWSKinesisVideoClient 생성]
// --------------------------------------------
AWSKinesisVideo awsKinesisVideoClient = new AWSKinesisVideoClient(credentials);
awsKinesisVideoClient.setRegion(Region.getRegion(REGION));
// --------------------------------------------
// [신호 채널 ARN 정보 조회 수행]
// --------------------------------------------
DescribeSignalingChannelRequest arn_request = new DescribeSignalingChannelRequest()
.withChannelName(CHANNEL_NAME);
DescribeSignalingChannelResult arn_result = awsKinesisVideoClient.describeSignalingChannel(arn_request);
ChannelInfo channelInfo = arn_result.getChannelInfo(); // TODO Get ChannelInfo
String CHANNEL_ARN = channelInfo.getChannelARN();
// --------------------------------------------
// [API 요청 서비스 명칭 선언]
// --------------------------------------------
String SERVICE_NAME = "kinesisvideo";
// ---------------------------------------------
// [AWS Signature V4 서명 적용]
// ---------------------------------------------
// import com.amazonaws.DefaultRequest;
// import com.amazonaws.Request;
// ---------------------------------------------
// import okhttp3.Request;
// import okhttp3.RequestBody;
// import okhttp3.Response;
// import okio.BufferedSink;
// ---------------------------------------------
com.amazonaws.Request<?> socket_sign_request = new DefaultRequest<Void>(SERVICE_NAME);
socket_sign_request.setHttpMethod(HttpMethodName.GET);
socket_sign_request.setEndpoint(URI.create(WSS_ENDPOINT)); // TODO Set URL
socket_sign_request.setEncodedResourcePath("/");
// Query Parameter 추가
Map<String, String> queryParams = new HashMap<>();
queryParams.put("X-Amz-ChannelARN", CHANNEL_ARN);
queryParams.put("X-Amz-ClientId", CLIENT_ID);
socket_sign_request.setParameters(queryParams);
// ---------------------------------------------
// [AWS 서명자 설정]
// ---------------------------------------------
AWS4Signer aws_socket_signer = new AWS4Signer();
aws_socket_signer.setServiceName(SERVICE_NAME);
aws_socket_signer.setRegionName(REGION);
Date expiration = new java.util.Date(System.currentTimeMillis() + 60 * 1000); // 1분
aws_socket_signer.presignRequest(socket_sign_request, credentials, expiration);
// ---------------------------------------------
// [실제 소켓 연결 Presigned URL 생성]
// ---------------------------------------------
String presignedUrl = "";
StringBuilder url = new StringBuilder(socket_sign_request.getEndpoint().toString());
url.append("?");
boolean first = true;
for (Map.Entry<String, String> entry : socket_sign_request.getParameters().entrySet()) {
if (!first) url.append("&");
first = false;
url.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name()))
.append("=")
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()));
}
presignedUrl = url.toString();
// ---------------------------------------------
// [OKHttp Request.Builder 생성]
// ---------------------------------------------
Request.Builder okSocketReqBuilder = new Request.Builder()
.url(presignedUrl)
.get();
// ---------------------------------------------
// [서명 헤더 추가]
// ---------------------------------------------
for (String key : socket_sign_request.getHeaders().keySet()) {
okSocketReqBuilder.header(key, socket_sign_request.getHeaders().get(key));
}
S_Log._W_("STEP :: Signaling :: WebSocket Connect :: Start", new String[]{"URL :: " + presignedUrl, "HEADER :: " + okSocketReqBuilder.build().headers()});
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[참고 사이트]
// --------------------------------------------------------------------------------------
[Aws SigV4 인증 및 서명 프로토콜 설명]
https://blog.naver.com/kkh0977/223874467995?trackingCode=blog_bloghome_searchlist
[WebRTC GetIceServerConfig TURN 릴레이 서버 IceServerList 설명]
https://blog.naver.com/kkh0977/224035896944
[WebRTC getSignalingChannelEndpoint HTTPS, WSS 사용 범위 정리]
https://blog.naver.com/kkh0977/224035890592
[WebRTC GetSignalingChannelEndpoint 신호 채널 엔드포인트 설명]
https://blog.naver.com/kkh0977/224035894347
// --------------------------------------------------------------------------------------
728x90
반응형
'Android' 카테고리의 다른 글
Comments
