How to execute an object file: Part 4, AArch64 edition

Post Syndicated from Oxana Kharitonova original http://blog.cloudflare.com/how-to-execute-an-object-file-part-4/


How to execute an object file: Part 4, AArch64 edition

Translating source code written in a high-level programming language into an executable binary typically involves a series of steps, namely compiling and assembling the code into object files, and then linking those object files into the final executable. However, there are certain scenarios where it can be useful to apply an alternate approach that involves executing object files directly, bypassing the linker. For example, we might use it for malware analysis or when part of the code requires an incompatible compiler. We’ll be focusing on the latter scenario: when one of our libraries needed to be compiled differently from the rest of the code. Learning how to execute an object file directly will give you a much better sense of how code is compiled and linked together.

To demonstrate how this was done, we have previously published a series of posts on executing an object file:

The initial posts are dedicated to the x86 architecture. Since then the fleet of our working machines has expanded to include a large and growing number of ARM CPUs. This time we’ll repeat this exercise for the aarch64 architecture. You can pause here to read the previous blog posts before proceeding with this one, or read through the brief summary below and reference the earlier posts for more detail. We might reiterate some theory as working with ELF files can be daunting, if it’s not your day-to-day routine. Also, please be mindful that for simplicity, these examples omit bounds and integrity checks. Let the journey begin!

Introduction

In order to obtain an object file or an executable binary from a high-level compiled programming language the code needs to be processed by three components: compiler, assembler and linker. The compiler generates an assembly listing. This assembly listing is picked up by the assembler and translated into an object file. All source files, if a program contains multiple, go through these two steps generating an object file for each source file. At the final step the linker unites all object files into one binary, additionally resolving references to the shared libraries (i.e. we don’t implement the printf function each time, rather we take it from a system library). Even though the approach is platform independent, the compiler output varies by platform as the assembly listing is closely tied to the CPU architecture.

GCC (GNU Compiler Collection) can run each step: compiler, assembler and linker separately for us:

main.c:

#include <stdio.h>

int main(void)
{
	puts("Hello, world!");
	return 0;
}

Compiler (output main.s – assembly listing):

$ gcc -S main.c
$ ls
main.c  main.s

Assembler (output main.o – an object file):

$ gcc -c main.s -o main.o
$ ls
main.c  main.o  main.s

Linker (main – an object file):

$ gcc main.o -o main
$ ls
main  main.c  main.o  main.s
$ ./main
Hello, world!

All the examples assume gcc is running on a native aarch64 architecture or include a cross compilation flag for those who want to reproduce and have no aarch64.

We have two object files in the output above: main.o and main. Object files are files encoded with the ELF (Executable and Linkable Format) standard. Although, main.o is an ELF file, it doesn’t contain all the information to be fully executable.

$ file main.o
main.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped

$ file main
main: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically
linked, interpreter /lib/ld-linux-aarch64.so.1,
BuildID[sha1]=d3ecd2f8ac3b2dec11ed4cc424f15b3e1f130dd4, for GNU/Linux 3.7.0, not stripped

The ELF File

The central idea of this series of blog posts is to understand how to resolve dependencies from object files without directly involving the linker. For illustrative purposes we generated an object file based on some C-code and used it as a library for our main program. Before switching to the code, we need to understand the basics of the ELF structure.

Each ELF file is made up of one ELF header, followed by file data. The data can include: a program header table, a section header table, and the data which is referred to by the program or section header tables.

The ELF Header

The ELF header provides some basic information about the file: what architecture the file is compiled for, the program entry point and the references to other tables.

The ELF Header:

$ readelf -h main
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x640
  Start of program headers:          64 (bytes into file)
  Start of section headers:          68576 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

The ELF Program Header

The execution process of almost every program starts from an auxiliary program, called loader, which arranges the memory and calls the program’s entry point. In the following output the loader is marked with a line “Requesting program interpreter: /lib/ld-linux-aarch64.so.1”. The whole program memory is split into different segments with associated size, permissions and type (which instructs the loader on how to interpret this block of memory). Because the execution process should be performed in the shortest possible time, the sections with the same characteristics and located nearby are grouped into bigger blocks — segments — and placed in the program header. We can say that the program header summarizes the types of data that appear in the section header.

The ELF Program Header:

$ readelf -Wl main

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x640
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R   0x8
  INTERP         0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R   0x1
      [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x00088c 0x00088c R E 0x10000
  LOAD           0x00fdc8 0x000000000001fdc8 0x000000000001fdc8 0x000270 0x000278 RW  0x10000
  DYNAMIC        0x00fdd8 0x000000000001fdd8 0x000000000001fdd8 0x0001e0 0x0001e0 RW  0x8
  NOTE           0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x0007a0 0x00000000000007a0 0x00000000000007a0 0x00003c 0x00003c R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x00fdc8 0x000000000001fdc8 0x000000000001fdc8 0x000238 0x000238 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .init_array .fini_array .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.gnu.build-id .note.ABI-tag 
   06     .eh_frame_hdr 
   07     
   08     .init_array .fini_array .dynamic .got 

The ELF Section Header

In the source code of high-level languages, variables, functions, and constants are mixed together. However, in assembly you might see that the data and instructions are separated into different blocks. The ELF file content is divided in an even more granular way. For example, variables with initial values are placed into different sections than the uninitialized ones. This approach optimizes for space, otherwise the values for uninitialized variables would be filled with zeros. Along with the space efficiency, there are security reasons for stratification — executable instructions can’t have writable permissions, while memory containing variables can’t be executable. The section header describes each of these sections.

The ELF Section Header:

$ readelf -SW main
There are 29 section headers, starting at offset 0x10be0:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000000238 000238 00001b 00   A  0   0  1
  [ 2] .note.gnu.build-id NOTE            0000000000000254 000254 000024 00   A  0   0  4
  [ 3] .note.ABI-tag     NOTE            0000000000000278 000278 000020 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0000000000000298 000298 00001c 00   A  5   0  8
  [ 5] .dynsym           DYNSYM          00000000000002b8 0002b8 0000f0 18   A  6   3  8
  [ 6] .dynstr           STRTAB          00000000000003a8 0003a8 000092 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          000000000000043a 00043a 000014 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0000000000000450 000450 000030 00   A  6   1  8
  [ 9] .rela.dyn         RELA            0000000000000480 000480 0000c0 18   A  5   0  8
  [10] .rela.plt         RELA            0000000000000540 000540 000078 18  AI  5  22  8
  [11] .init             PROGBITS        00000000000005b8 0005b8 000018 00  AX  0   0  4
  [12] .plt              PROGBITS        00000000000005d0 0005d0 000070 00  AX  0   0 16
  [13] .text             PROGBITS        0000000000000640 000640 000134 00  AX  0   0 64
  [14] .fini             PROGBITS        0000000000000774 000774 000014 00  AX  0   0  4
  [15] .rodata           PROGBITS        0000000000000788 000788 000016 00   A  0   0  8
  [16] .eh_frame_hdr     PROGBITS        00000000000007a0 0007a0 00003c 00   A  0   0  4
  [17] .eh_frame         PROGBITS        00000000000007e0 0007e0 0000ac 00   A  0   0  8
  [18] .init_array       INIT_ARRAY      000000000001fdc8 00fdc8 000008 08  WA  0   0  8
  [19] .fini_array       FINI_ARRAY      000000000001fdd0 00fdd0 000008 08  WA  0   0  8
  [20] .dynamic          DYNAMIC         000000000001fdd8 00fdd8 0001e0 10  WA  6   0  8
  [21] .got              PROGBITS        000000000001ffb8 00ffb8 000030 08  WA  0   0  8
  [22] .got.plt          PROGBITS        000000000001ffe8 00ffe8 000040 08  WA  0   0  8
  [23] .data             PROGBITS        0000000000020028 010028 000010 00  WA  0   0  8
  [24] .bss              NOBITS          0000000000020038 010038 000008 00  WA  0   0  1
  [25] .comment          PROGBITS        0000000000000000 010038 00001f 01  MS  0   0  1
  [26] .symtab           SYMTAB          0000000000000000 010058 000858 18     27  66  8
  [27] .strtab           STRTAB          0000000000000000 0108b0 00022c 00      0   0  1
  [28] .shstrtab         STRTAB          0000000000000000 010adc 000103 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

Executing example from Part 1 on aarch64

Actually, our initial code from Part 1 works on aarch64 as is!

Let’s have a quick summary about what was done in the code:

  1. We need to find the code of two functions (add5 and add10) in the .text section of our object file (obj.o)
  2. Load the functions in the executable memory
  3. Return the memory locations of the functions to the main program

There is one nuance: even though all the sections are in the section header, neither of them have a string name. Without the names we can’t identify them. However, having an additional character field for each section in the ELF structure would be inefficient for the space — it must be limited by some maximum length and those names which are shorter would leave the space unfilled. Instead, ELF provides an additional section, .shstrtab. This string table concatenates all the names where each name ends with a null terminated byte. We can iterate over the names and match with an offset held by other sections to reference their name. But how do we find .shstrtab itself if we don’t have a name? To solve this chicken and egg problem, the ELF program header provides a direct pointer to .shstrtab. The similar approach is applied to two other sections: .symtab and .strtab. Where .symtab contains all information about the symbols and .strtab holds the list of symbol names. In the code we work with these tables to resolve all their dependencies and find our functions.

Executing example from Part 2 on aarch64

At the beginning of the second blog post we made the function add10 depend on add5 instead of being self-contained. This is the first time when we faced relocations. Relocations is the process of loading symbols defined outside the current scope. The relocated symbols can present global or thread-local variables, constant, functions, etc. We’ll start from checking assembly instructions which trigger relocations and uncovering how the ELF format handles them in a more general way.

After making add10 depend on add5 our aarch64 version stopped working as well, similarly to the x86. Let’s take a look at assembly listing:

$ objdump --disassemble --section=.text obj.o

obj.o:     file format elf64-littleaarch64


Disassembly of section .text:

0000000000000000 <add5>:
   0:	d10043ff 	sub	sp, sp, #0x10
   4:	b9000fe0 	str	w0, [sp, #12]
   8:	b9400fe0 	ldr	w0, [sp, #12]
   c:	11001400 	add	w0, w0, #0x5
  10:	910043ff 	add	sp, sp, #0x10
  14:	d65f03c0 	ret

0000000000000018 <add10>:
  18:	a9be7bfd 	stp	x29, x30, [sp, #-32]!
  1c:	910003fd 	mov	x29, sp
  20:	b9001fe0 	str	w0, [sp, #28]
  24:	b9401fe0 	ldr	w0, [sp, #28]
  28:	94000000 	bl	0 <add5>
  2c:	b9001fe0 	str	w0, [sp, #28]
  30:	b9401fe0 	ldr	w0, [sp, #28]
  34:	94000000 	bl	0 <add5>
  38:	a8c27bfd 	ldp	x29, x30, [sp], #32
  3c:	d65f03c0 	ret

Have you noticed that all the hex values in the second column are exactly the same length, in contrast with the instructions lengths seen for x86 in Part 2 of our series? This is because all Armv8-A instructions are presented in 32 bits. Since it is impossible to encode every immediate value into less than 32 bits, some operations require more than one instruction, as we’ll see later. For now, we’re interested in one instruction - bl (branch with link) on rows 28 and 34. The bl is a “jump” instruction, but before the jump it preserves the next instruction after the current one in the link register (lr). When the callee finishes execution the caller address is recovered from lr. Usually, the aarch64 instructions reserve the last 6 bits [31:26] for opcode and some auxiliary fields such as running architecture (32 or 64 bits), condition flag and others. Remaining bits are shared between arguments like source register, destination register and immediate value. Since the bl instruction does not require a source or destination register, the full 26 bits can be used to encode the immediate offset instead. However, 26 bits can only encode a small range (+/-32 MB), but because the jump can only target a beginning of an instruction, it must always be aligned to 4 bytes, which increases the effective range of the encoded immediate fourfold, to +/-128 MB.

Similarly to what we did in Part 2 we’re going to resolve our relocations – first by manually calculating the correct addresses and then by using an approach similar to what the linker does. The current value of our bl instruction is 94000000 or in binary representation 10010100000000000000000000000000. All 26 bits are zeros, so we don’t jump anywhere. The address is calculated by an offset from the current program counter (pc), which can be positive or negative. In our case we expect it to be -0x28 and -0x34. As described above, it should be divided by 4 and taken as two’s complements: -0x28 / 4 = -0xA == 0xFFFFFFF6 and -0x34 / 4 = -0xD == 0xFFFFFFF3. From these values we need to take the lower 26 bits and concatenate them with the initial 6 bits to get the final instruction. So, the final ones will be: 10010111111111111111111111110110 == 0x97FFFFF6 and 10010111111111111111111111110011 == 0x97FFFFF3. Have you noticed that all the distance calculations are done relative to the bl (or current pc), not the next instruction as in x86?

Let’s add to the code and execute:

... 

static void parse_obj(void)
{
	...
	/* copy the contents of `.text` section from the ELF file */
	memcpy(text_runtime_base, obj.base + text_hdr->sh_offset, text_hdr->sh_size);

	*((uint32_t *)(text_runtime_base + 0x28)) = 0x97FFFFF6;
	*((uint32_t *)(text_runtime_base + 0x34)) = 0x97FFFFF3;

	/* make the `.text` copy readonly and executable */
	if (mprotect(text_runtime_base, page_align(text_hdr->sh_size), PROT_READ | PROT_EXEC)) {
	...

Compile and run:

$ gcc -o loader loader.c
$ ./loader
Executing add5...
add5(42) = 47
Executing add10...
add10(42) = 52

It works! But this is not how the linker handles the relocations. The linker resolves relocation based on the type and formula assigned to this type. In our Part 2 we investigated it quite well. Here again we need to find the type and check the formula for this type:

$ readelf --relocs obj.o

Relocation section '.rela.text' at offset 0x228 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000028  000a0000011b R_AARCH64_CALL26  0000000000000000 add5 + 0
000000000034  000a0000011b R_AARCH64_CALL26  0000000000000000 add5 + 0

Relocation section '.rela.eh_frame' at offset 0x258 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
00000000001c  000200000105 R_AARCH64_PREL32  0000000000000000 .text + 0
000000000034  000200000105 R_AARCH64_PREL32  0000000000000000 .text + 18

Our Type is R_AARCH64_CALL26 and the formula for it is:

ELF64 Code

Name

Operation

283

R_<CLS>_CALL26

S + A – P

where:

  • S (when used on its own) is the address of the symbol
  • A is the addend for the relocation
  • P is the address of the place being relocated (derived from r_offset)

Here are the relevant changes to loader.c:

/* Replace `#define R_X86_64_PLT32 4` with our Type */
#define R_AARCH64_CALL26 283
...

static void do_text_relocations(void)
{
	...
	uint32_t val;

	switch (type)
	{
	case R_AARCH64_CALL26:
		/* The mask separates opcode (6 bits) and the immediate value */
		uint32_t mask_bl = (0xffffffff << 26);
		/* S+A-P, divided by 4 */
		val = (symbol_address + relocations[i].r_addend - patch_offset) >> 2;
		/* Concatenate opcode and value to get final instruction */
		*((uint32_t *)patch_offset) &= mask_bl;
		val &= ~mask_bl;
		*((uint32_t *)patch_offset) |= val;
		break;
	}
	...
}

Compile and run:

$ gcc -o loader loader.c 
$ ./loader
Calculated relocation: 0x97fffff6
Calculated relocation: 0x97fffff3
Executing add5...
add5(42) = 47
Executing add10...
add10(42) = 52

So far so good. The next challenge is to add constant data and global variables to our object file and check relocations again:

$ readelf --relocs --wide obj.o

Relocation section '.rela.text' at offset 0x388 contains 8 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000000  0000000500000113 R_AARCH64_ADR_PREL_PG_HI21 0000000000000000 .rodata + 0
0000000000000004  0000000500000115 R_AARCH64_ADD_ABS_LO12_NC 0000000000000000 .rodata + 0
000000000000000c  0000000300000113 R_AARCH64_ADR_PREL_PG_HI21 0000000000000000 .data + 0
0000000000000010  0000000300000115 R_AARCH64_ADD_ABS_LO12_NC 0000000000000000 .data + 0
0000000000000024  0000000300000113 R_AARCH64_ADR_PREL_PG_HI21 0000000000000000 .data + 0
0000000000000028  0000000300000115 R_AARCH64_ADD_ABS_LO12_NC 0000000000000000 .data + 0
0000000000000068  000000110000011b R_AARCH64_CALL26       0000000000000040 add5 + 0
0000000000000074  000000110000011b R_AARCH64_CALL26       0000000000000040 add5 + 0
...

We have even two new relocations: R_AARCH64_ADD_ABS_LO12_NC and R_AARCH64_ADR_PREL_PG_HI21. Their formulas are:

ELF64 Code

Name

Operation

275

R_<CLS>_ ADR_PREL_PG_HI21

Page(S+A) – Page(P)

277

R_<CLS>_ ADD_ABS_LO12_NC

S + A

where:

Page(expr) is the page address of the expression expr, defined as (expr & ~0xFFF). (This applies even if the machine page size supported by the platform has a different value.)

It’s a bit unclear why we have two new types, while in x86 we had only one. Let’s investigate the assembly code:

$ objdump --disassemble --section=.text obj.o

obj.o:     file format elf64-littleaarch64


Disassembly of section .text:

0000000000000000 <get_hello>:
   0:	90000000 	adrp	x0, 0 <get_hello>
   4:	91000000 	add	x0, x0, #0x0
   8:	d65f03c0 	ret

000000000000000c <get_var>:
   c:	90000000 	adrp	x0, 0 <get_hello>
  10:	91000000 	add	x0, x0, #0x0
  14:	b9400000 	ldr	w0, [x0]
  18:	d65f03c0 	ret

000000000000001c <set_var>:
  1c:	d10043ff 	sub	sp, sp, #0x10
  20:	b9000fe0 	str	w0, [sp, #12]
  24:	90000000 	adrp	x0, 0 <get_hello>
  28:	91000000 	add	x0, x0, #0x0
  2c:	b9400fe1 	ldr	w1, [sp, #12]
  30:	b9000001 	str	w1, [x0]
  34:	d503201f 	nop
  38:	910043ff 	add	sp, sp, #0x10
  3c:	d65f03c0 	ret

We see that all adrp instructions are followed by add instructions. The add instruction adds an immediate value to the source register and writes the result to the destination register. The source and destination registers can be the same, the immediate value is 12 bits. The adrp instruction generates a pc-relative (program counter) address and writes the result to the destination register. It takes pc of the instruction itself and adds a 21-bit immediate value shifted left by 12 bits. If the immediate value weren’t shifted it would lie in a range of +/-1 MB memory, which isn’t enough. The left shift increases the range up to +/-1 GB. However, because the 12 bits are masked out with the shift, we need to store them somewhere and restore later. That’s why we see add instruction following adrp and two types instead of one. Also, it’s a bit tricky to encode adrp: 2 low bits of immediate value are placed in the position 30:29 and the rest in the position 23:5. Due to size limitations, the aarch64 instructions try to make the most out of 32 bits.

In the code we are going to use the formulas to calculate the values and description of adrp and add instructions to obtain the final opcode:

#define R_AARCH64_CALL26 283
#define R_AARCH64_ADD_ABS_LO12_NC 277
#define R_AARCH64_ADR_PREL_PG_HI21 275
...

{
case R_AARCH64_CALL26:
	/* The mask separates opcode (6 bits) and the immediate value */
	uint32_t mask_bl = (0xffffffff << 26);
	/* S+A-P, divided by 4 */
	val = (symbol_address + relocations[i].r_addend - patch_offset) >> 2;
	/* Concatenate opcode and value to get final instruction */
	*((uint32_t *)patch_offset) &= mask_bl;
	val &= ~mask_bl;
	*((uint32_t *)patch_offset) |= val;
	break;
case R_AARCH64_ADD_ABS_LO12_NC:
	/* The mask of `add` instruction to separate 
	* opcode, registers and calculated value 
	*/
	uint32_t mask_add = 0b11111111110000000000001111111111;
	/* S + A */
	uint32_t val = *(symbol_address + relocations[i].r_addend);
	val &= ~mask_add;
	*((uint32_t *)patch_offset) &= mask_add;
	/* Final instruction */
	*((uint32_t *)patch_offset) |= val;
case R_AARCH64_ADR_PREL_PG_HI21:
	/* Page(S+A)-Page(P), Page(expr) is defined as (expr & ~0xFFF) */
	val = (((uint64_t)(symbol_address + relocations[i].r_addend)) & ~0xFFF) - (((uint64_t)patch_offset) & ~0xFFF);
	/* Shift right the calculated value by 12 bits.
	 * During decoding it will be shifted left as described above, 
	 * so we do the opposite.
	*/
	val >>= 12;
	/* Separate the lower and upper bits to place them in different positions */ 
	uint32_t immlo = (val & (0xf >> 2)) << 29 ;
	uint32_t immhi = (val & ((0xffffff >> 13) << 2)) << 22;
	*((uint32_t *)patch_offset) |= immlo;
	*((uint32_t *)patch_offset) |= immhi;
	break;
}

Compile and run:

$ gcc -o loader loader.c 
$ ./loader
Executing add5...
add5(42) = 47
Executing add10...
add10(42) = 52
Executing get_hello...
get_hello() = Hello, world!
Executing get_var...
get_var() = 5
Executing set_var(42)...
Executing get_var again...
get_var() = 42

It works! The final code is here.

Executing example from Part 3 on aarch64

Our Part 3 is about resolving external dependencies. When we write code we don’t think much about how to allocate memory or print debug information to the console. Instead, we involve functions from the system libraries. But the code of system libraries needs to be passed through to our programs somehow. Additionally, for optimization purposes, it would be nice if this code would be stored in one place and shared between all programs. And another wish — we don’t want to resolve all the functions and global variables from the libraries, only those which we need and at those times when we need them. To solve these problems, ELF introduced two sections: PLT (the procedure linkage table) and GOT (the global offset table). The dynamic loader creates a list which contains all external functions and variables from the shared library, but doesn’t resolve them immediately; instead they are placed in the PLT section. Each external symbol is presented by a small function, a stub, e.g. puts@plt. When an external symbol is requested, the stub checks if it was resolved previously. If not, the stub searches for an absolute address of the symbol, returns to the requester and writes it in the GOT table. The next time, the address returns directly from the GOT table.

In Part 3 we implemented a simplified PLT/GOT resolution. Firstly, we added a new function say_hello in the obj.c, which calls unresolved system library function puts. Further we added an optional wrapper my_puts in the loader.c. The wrapper isn’t required, we could’ve resolved directly to a standard function, but it’s a good example of how the implementation of some functions can be overwritten with custom code. In the next steps we added our PLT/GOT resolution:

Basically, we created a small stub with assembly code (our jumptable) to resolve the global address of our my_puts wrapper and jump to it.

The approach for aarch64 is the same. But the jumptable is very different as it consists of different assembly instructions.

The big difference here compared to the other parts is that we need to work with a 64-bit address for the GOT resolution. Our custom PLT or jumptable is placed close to the main code of obj.c and can operate with the relative addresses as before. For the GOT or referencing my_puts wrapper we’ll use different branch instructions — br or blr. These instructions branch to the register, where the aarch64 registers can hold 64-bit values.

We can check how it resolves with the native PLT/GOT in our loader assembly code:

$ objdump --disassemble --section=.text loader
...
1d2c:	97fffb45 	bl	a40 <puts@plt>
1d30:	f94017e0 	ldr	x0, [sp, #40]
1d34:	d63f0000 	blr	x0
...

The first instruction is bl jump to puts@plt stub. The next ldr instruction tells us that some value was loaded into the register x0 from the stack. Each function has its own stack frame to hold the local variables. The last blr instruction makes a jump to the address stored in x0 register. There is an agreement in the register naming: if the stored value is 64-bits then the register is called x0-x30; if only 32-bits are used then it’s called w0-w30 (the value will be stored in the lower 32-bits and upper 32-bits will be zeroed).

We need to do something similar — place the absolute address of our my_puts wrapper in some register and call br on this register. We don’t need to store the link before branching, the call will be returned to say_hello from obj.c, which is why a plain br will be enough. Let’s check an assembly of simple C-function:

hello.c:

#include <stdint.h>

void say_hello(void)
{
    uint64_t reg = 0x555555550c14;
}
$ gcc -c hello.c
$ objdump --disassemble --section=.text hello.o

hello.o:     file format elf64-littleaarch64


Disassembly of section .text:

0000000000000000 <say_hello>:
   0:	d10043ff 	sub	sp, sp, #0x10
   4:	d2818280 	mov	x0, #0xc14                 	// #3092
   8:	f2aaaaa0 	movk	x0, #0x5555, lsl #16
   c:	f2caaaa0 	movk	x0, #0x5555, lsl #32
  10:	f90007e0 	str	x0, [sp, #8]
  14:	d503201f 	nop
  18:	910043ff 	add	sp, sp, #0x10
  1c:	d65f03c0 	ret

The number 0x555555550c14 is the address returned by lookup_ext_function. We’ve printed it out to use as an example, but any 48-bits hex value can be used.

In our output we see that the value was split in three sections and written in x0 register with three instructions: one mov and two movk. The documentation says that there are only 16 bits for the immediate value, but a shift can be applied (in our case left shift lsl).

However, we can’t use x0 in our context. By convention the registers x0-x7 are caller-saved and used to pass function parameters between calls to other functions. Let’s use x9 then.

We need to modify our loader. Firstly let’s change the jumptable structure.

loader.c:

...
struct ext_jump {
	uint32_t instr[4];
};
...

As we saw above, we need four instructions: mov, movk, movk, br. We don’t need a stack frame as we aren’t preserving any local variables. We just want to load the address into the register and branch to it. But we can’t write human-readable code

e.g. mov  x0, #0xc14 into instructions, we need machine binary or hex representation, e.g. d2818280.

Let’s write a simple assembly code to get it:

plt.s:

.global _start

_start: mov     x9, #0xc14 
        movk    x9, #0x5555, lsl #16
        movk    x9, #0x5555, lsl #32
        br      x9
$ as -o hw.o hw.s
$ objdump --disassemble --section=.text hw.o

hw.o:     file format elf64-littleaarch64


Disassembly of section .text:

0000000000000000 <_start>:
   0:	d2818289 	mov	x9, #0xc14                 	// #3092
   4:	f2aaaaa9 	movk	x9, #0x5555, lsl #16
   8:	f2caaaa9 	movk	x9, #0x5555, lsl #32
   c:	d61f0120 	br	x9

Almost done! But there’s one more thing to consider. Even if the value 0x555555550c14 is a real my_puts wrapper address, it will be different on each run if ASLR(Address space layout randomization) is enabled. We need to patch these instructions to put the value which will be returned by lookup_ext_function on each run. We’ll split the obtained value in three parts, 16-bits each, and replace them in our mov and movk instructions according to the documentation, similar to what we did before for our second part.

if (symbols[symbol_idx].st_shndx == SHN_UNDEF) {
	static int curr_jmp_idx = 0;

	uint64_t addr = lookup_ext_function(strtab +  symbols[symbol_idx].st_name);
	uint32_t mov = 0b11010010100000000000000000001001 | ((addr << 48) >> 43);
	uint32_t movk1 = 0b11110010101000000000000000001001 | (((addr >> 16) << 48) >> 43);
	uint32_t movk2 = 0b11110010110000000000000000001001 | (((addr >> 32) << 48) >> 43);
	jumptable[curr_jmp_idx].instr[0] = mov;         // mov  x9, #0x0c14
	jumptable[curr_jmp_idx].instr[1] = movk1;       // movk x9, #0x5555, lsl #16
	jumptable[curr_jmp_idx].instr[2] = movk2;       // movk x9, #0x5555, lsl #32
	jumptable[curr_jmp_idx].instr[3] = 0xd61f0120;  // br   x9

	symbol_address = (uint8_t *)(&jumptable[curr_jmp_idx].instr[0]);
	curr_jmp_idx++;
} else {
	symbol_address = section_runtime_base(&sections[symbols[symbol_idx].st_shndx]) + symbols[symbol_idx].st_value;
}
uint32_t val;
switch (type)
{
case R_AARCH64_CALL26:
	/* The mask separates opcode (6 bits) and the immediate value */
	uint32_t mask_bl = (0xffffffff << 26);
	/* S+A-P, divided by 4 */
	val = (symbol_address + relocations[i].r_addend - patch_offset) >> 2;
	/* Concatenate opcode and value to get final instruction */
	*((uint32_t *)patch_offset) &= mask_bl;
	val &= ~mask_bl;
	*((uint32_t *)patch_offset) |= val;
	break;
...

In the code we took the address of the first instruction &jumptable[curr_jmp_idx].instr[0] and wrote it in the symbol_address, further because the type is still R_AARCH64_CALL26 it will be put into bl – jump to the relative address. Where our relative address is the first mov instruction. The whole jumptable code will be executed and finished with the blr instruction.

The final run:

$ gcc -o loader loader.c
$ ./loader
Executing add5...
add5(42) = 47
Executing add10...
add10(42) = 52
Executing get_hello...
get_hello() = Hello, world!
Executing get_var...
get_var() = 5
Executing set_var(42)...
Executing get_var again...
get_var() = 42
Executing say_hello...
my_puts executed
Hello, world!

The final code is here.

Summary

There are several things we covered in this blog post. We gave a brief introduction on how the binary got executed on Linux and how all components are linked together. We saw a big difference between x86 and aarch64 assembly. We learned how we can hook into the code and change its behavior. But just as it was said in the first blog post of this series, the most important thing is to remember to always think about security first. Processing external inputs should always be done with great care. Bounds and integrity checks have been omitted for the purposes of keeping the examples short, so readers should be aware that the code is not production ready and is designed for educational purposes only.

Security updates for Friday

Post Syndicated from jake original https://lwn.net/Articles/951801/

Security updates have been issued by Debian (webkit2gtk), Fedora (microcode_ctl, pack, and tigervnc), Slackware (gimp), SUSE (frr, gcc13, go1.20, go1.20-openssl, go1.21, go1.21-openssl, libnbd, libxml2, python-Pillow, python-urllib3, and xen), and Ubuntu (intel-microcode and openvpn).

Игрите с дерогацията и „Лукойл“

Post Syndicated from Емилия Милчева original https://www.toest.bg/igrite-s-derogatsiyata-i-lukoil/

Игрите с дерогацията и „Лукойл“

Политиката и петролът винаги са били скачени съдове и България, на чиято територия е най-голямата рафинерия в Югоизточна Европа, не прави изключение. За бургаското предприятие, собственост на най-голямата частна руска компания – „Лукойл“, но главно за българските потребители и държавата, въпросът е кой ще го притежава в близко бъдеще и кой ще се възползва при евентуална сделка и/или необходимостта от бърз внос на горива. 

Смяна на собствеността

Темата излезе на дневен ред след европейското ембарго за внос на руски суров петрол по море, но също и в контекста на засилващите се европейски санкции срещу Русия. Целите на Европейския съюз са до 2030 г. да премахне изцяло енергийната си зависимост от Русия от нефт и газ. България получи изключение от петролното ембарго за две години и половина – до края на 2024 г., по искане на тогавашния премиер Кирил Петков („Продължаваме промяната“) миналото лято. Но в Италия се наложи „Лукойл“ да продаде рафинерията си в Сицилия буквално за няколко месеца – за 1,5 млрд. евро по информация на Financial Times. 

Тези обстоятелства създадоха обосновани предположения, че същата съдба ще сполети и „Лукойл Нефтохим“ – и премиерът Николай Денков, и министърът на финансите Асен Василев неслучайно обявиха, че е проявен инвеститорски интерес. От Litasco – швейцарската компания, собственик на „Лукойл“, отрекоха, но неписаното правило е, че шумът при такива сделки вреди. Освен рафинерията, „Лукойл“ притежава и над 220 бензиностанции, нефтобази, складове, продуктопровод и др. („Газпром“, който миналата пролет прекрати едностранно доставките на газ за България, вече продава бензиностанциите си.) Запитан за евентуална сделка, тази седмица министър-председателят каза, че знае за интерес от различни страни, но правителството не е част от преговорния процес. 

Интерес има, но дали са напреднали преговорите, никой от нас не може да каже.

Схемите са две: едната е Litasco да продаде българската си компания, другата – най-напред в рафинерията да влезе особен търговски управител, на когото се разрешава да управлява максимум 12 месеца според Закона за контрол по прилагане на ограничителните мерки с оглед на действията на Русия, дестабилизиращи положението в Украйна. Този управител се избира по предложение на правителството, отговорен е пред Народното събрание и е контролиран от парламентарната Комисия по икономическа политика и иновации. Неин председател е Хамид Хамид от ДПС. 

Законът не дава право на особения търговски управител да се разпорежда със собствеността, но чрез него държавата би могла да повлияе на евентуални инвеститори. Той поема оперативното управление, когато има опасност от засягане на националната сигурност или от нарушаване на ограничителни мерки от международни организации, задължителни за България. 

Ето че тази седмица председателят на парламентарната група на ДПС Делян Пеевски и председателят на енергийната комисия в 49-тото НС Делян Добрев от ГЕРБ сезираха прокуратурата, че „Лукойл“ нарушава европейските санкции. Повод стана разследване на изданието „Политико“, според което рафинерията e преработвала и продавала в чужбина, включително и в страните от ЕС, горива, произведени от руски петрол. Според ДПС компанията го е правила под прикритието на износ за трети страни, претоварвайки ги в открито море. „Лукойл“ отрече и заяви, че ще съдейства на прокуратурата. Агенция „Митници“ в публично изявление опроверга твърденията на политиците, че бургаската рафинерия нарушава условията на получената дерогация за износ на нефтопродукти. Премиерът Денков също каза, че няма данни за нарушения на санкциите.

Пресата се засилва

Властта обаче постепенно увеличава натиска върху руската компания. През септември концесията на руската компания за пристанище „Росенец“, откъдето влиза целият суров петрол, който рафинерията преработва, бе прекратена. Сега държавата оперира порта чрез предприятието си „Пристанищна инфраструктура“.

Парламентът прие и законова промяна в срок от 12 месеца 100% от задължителните запаси на нефт и нефтопродукти да се съхраняват на територията на страната. Преди това ограничението за съхраняване на горива за извънредни ситуации в друга държава членка на ЕС бе 50%.

Подобно изискване означава, че са необходими нови складови бази, а това ще рече и инвестиции за строителството им – 300 млн. евро според министъра на финансите Асен Василев. 

След като възроптаха търговците на горива, според които срокът е твърде кратък, за да успеят, се ядосаха и от ГЕРБ и ДПС. Те поискаха да се върне ограничението за 50-те процента до 30 юни 2024 г., а след това до 30% от всички запаси да бъдат държани в чужбина, както и Държавният резерв да поеме управлението на базите за съхранение на горива на „Лукойл Нефтохим“ в страната. Така дни след обнародването на първоначалната промяна в Държавен вестник бе върнато старото положение с аргумента, че предишната разпоредба обслужва „Лукойл“, който държи 92% от складовете.

„Лукойл Нефтохим“ трябва да внесе и още 270 млн. лв. данък печалба в добавка към авансовата вноска от 89 млн. лв., направена по-рано през годината. Служебният премиер Гълъб Донев обещаваше постъпления от поне 600 млн. лв. годишно, след като компанията премести дейността си в България от 2023 г., но няма и помен от тях. Причината за очакваните милиони е, че от тази година освен 10% данък печалба „Лукойл“ трябва да плаща и „солидарна вноска“, определена от Европейската комисия на 33% от реализираната свръхпечалба на петролните и газовите компании в ЕС заради високите цени на горивата. Но със законови промени 33-те процента бяха повишени на 50 за последното тримесечие на 2023 г. Правителството разчита на тези средства, тъй като милионите по Плана за възстановяване и устойчивост може и да не бъдат получени до края на годината (на тяхната липса се дължи и дефицитът в бюджета).

Рафинерията е задължена да прави и вноски във фонд „Сигурност на електроенергийната система“, които се равняват на ценовата разлика между евтиния руски петрол „Уралс“ и европейския сорт „Брент“. Мярката беше предложена от Делян Добрев – за да се финансира подпомагането на транспортните разходи на уязвимите групи, но санкцията за неизпълнението ѝ е нищожна – 10 000 лв. Законът така и не бе задействан заради заложеното в него изискване за нотификация от ЕК, макар да не бе необходима, а служебното правителство така и не я поиска от Брюксел. Кабинетът на ПП–ДБ поиска такава нотификация и разработи и схеми за подпомагане.

Въпреки това Добрев непрекъснато атакува кабинета на Денков с любимите си въпроси защо не прибира 73 стотинки (най-напред беше левче) от цените на горивата. България потребява годишно около 2,5–3 млн. тона от произвежданите от рафинерията близо 7 млн. тона горива, останалата продукция е за износ. Но не и за Украйна. Украинските спецслужби вкараха в забранителен списък петролните бази в Бургас, Варна, Пловдив, Бяла, също и на „Инса Ойл“ в Белозем, тъй като Киев прекратява вноса на руски горива. Всеки търговец, който иска да вкара петролни продукти, трябва да представи пълна документация за произхода им.

Пеевски се подготвя отрано 

През септември 49-тият парламент прие на първо четене законопроект за скрининг на преките чуждестранни инвестиции от над 1 млн. лв. Като негов основен автор е представен Пеевски. Ако законопроектът бъде приет, това означава, че инвестиции от над 1 млн. евро (колкото луксозна къща в София), свързани със сигурността и обществения ред, ще се разрешават от специално създаден за целта Междуведомствен съвет. Енергетиката попада в обхвата. Председател на Съвета би следвало да е един от заместник-министрите на иновациите и растежа, а десет министерства и спецслужби да имат представители в него. 

Чуждестранните инвеститори са длъжни да подават заявление за разрешение чрез Българската агенция за инвестиции (БАИ). Механизмът, макар и изискван от ЕС по силата на Регламент 2019/452 и мотивиран с бариера пред проникването на руски капитали, до голяма степен повтаря схемата, действала за „златните паспорти“. И при нея БАИ издаваше сертификати за инвестиции и така гарантираше, че са направени. Приеме ли се скринингът, през него ще мине и кандидатът за „Лукойл“, а властта ще определи става или не става.

Сега обаче отпадането на дерогацията е инструментът за извиването на ръцете на правителството. Отново тандемът „Деляновците“ иска премахването ѝ в 3-дневен срок. Предупрежденията в доклад на ДАНС, че горивата ще поскъпнат, обаче бяха чути от парламента, който отхвърли законопроекта им на първо четене. Интересно е, че правителството и ПП–ДБ приемат аргументи от ДАНС, чийто шеф настояват да бъде сменен. Едва ли Пеевски и Добрев са вярвали, че законопроектът им ще бъде приет – така ще предизвикат гражданско недоволство при хаос на пазара и повишение на цените. Но пък продължават с натиска върху правителството и премиерът Денков свика дори Съвета по сигурността заради искането им. 

Няма съмнение, че срокът, договорен от правителството с „Лукойл Нефтохим Бургас“, ще бъде съкратен – парламентът беше приел отпадането на дерогацията да стане по график до 1 октомври догодина. Предложението на ПП–ДБ е това да бъде през март – тогава е насрочена и ротацията между ГЕРБ и ПП–ДБ. Начело на правителството ще застане Мария Габриел, Денков поема поста министър на образованието, а най-вероятно ще има и смени на министри.

До отпадането на дерогацията, когато и да е тя, рафинерията трябва да е готова да премине изцяло към преработване на неруски петрол. Пред bTV съпредседателят на ПП Кирил Петков заяви, че към момента тя преработва около 48% неруски нефт – останалата част е руски. Цялостното му премахване не може да стане изведнъж, тъй като може да предизвика повреди и аварии. Тестването на различните сортове отнема време, а след определянето им следва и сключване на договори за доставка. Преминаването към преработка на неруски нефт означава, че вече няма да има танкери от Новоросийск, които стигат за 36 часа до порт „Росенец“, а за поне 600 часа и преминават през Босфора, както обясниха наскоро от „Лукойл“.

Пропагандни балони

Излиза, че ГЕРБ и ДПС са евроатлантическо(то) мнозинство в 49-тия парламент, защото настояват незабавно да отпадне дерогацията – за да не финансират руските пари от петрол войната срещу Украйна. Пеевски предупреди ПП–ДБ да прочетат знаците и да не рушат това евроатлантическо мнозинство. Може ли да се вярва на тази формална истина, твърдяна от санкциониран по Глобалния закон „Магнитски“?

Регулярно е участвал в корупция, като си е служил с търговия с влияние и подкупи, за да се защити от обществен контрол и за да упражнява контрол върху ключови институции и сектори в българското общество.

Не може да ѝ се вярва, защото през вече продадената медийна група на Пеевски нахлу проруската пропаганда. Защото в съюз с Цветан Василев и руски капитали бе наложена КТБ. Защото нищо от делата му не потвърждава евроатлантическата каузалност. Конверсията на Пеевски е възможна само ако има бизнес интереси. 

И той, и БСП обаче твърдят, че управлява „прокремълски кабинет“. Пеевски дори отиде по-далеч, наричайки гласувалите срещу светкавичното отпадане БСП и „Възраждане“ и въздържалите се от ПП–ДБ „коалиция Путин“. Съидейникът му Делян Добрев пък отсъстваше от пленарната зала.

По БНР политологът проф. Димитър Вацов коментира: 

Става дума за един по-цялостен пазарлък от страна на ГЕРБ и ДПС – значителна част от икономическите лостове на държавата да дойдат пак при тях. 

Подготвяйки ротацията, те се пазарят както и за бюджета за догодина, а стрелите са насочени към финансовия министър, смята той.

Радикализирането на ГЕРБ и ДПС по отношение на „Лукойл“ е повече от странно. От приватизацията на „Нефтохим“ досега „Лукойл“ се е превърнал в синоним на обгрижван от държавата монопол, успешно и законово избягвал плащането на данък печалба в България повече от 15 години. За първи път го направи през 2022 г. с едни 75 млн. лева. (Без)действието на българските регулатори в лицето на Комисията за защита на конкуренцията (КЗК) спомогна за диктатурата на пазара на едро. Едва в края на 2021 г., когато политическата конюнктура се беше променила и ГЕРБ и Бойко Борисов вече не управляваха, КЗК изведнъж забеляза, че „Лукойл“ злоупотребява с господстващо положение, тъй като не допуска други до данъчните си складове за горива и до продуктопроводите си – така пречи на вноса на горива и на конкуренцията на пазара. Комисията, начело на която е кадър на ГЕРБ, санкционира „Лукойл“ с близо 68 млн. лв. и заради ценови натиск върху конкурентите на пазара.

Демонстрирайки сила, ГЕРБ и ДПС провалиха гласуването на втория вот на недоверие към правителството, поискан от БСП заради провал в политиките по сигурността. Сега парламентът се намира в безпрецедентната ситуация на неприключило прегласуване на вот на недоверие, тъй като кворумът в пленарната зала беше провален. Лидерът на ГЕРБ Бойко Борисов, чийто партньор на карти дълги години бе директорът на „Лукойл България“ Валентин Златев, заяви в кулоарите, че „Лукойл“ е частна компания, пряко подчинена на Кремъл, след като по-рано БСП обвиниха мнозинството, че искат да си я разделят.

Как така заради тоя петрол пусти и тези пари явно са готови да падне правителството, да се съберат с опозиционните уж партии – „Възраждане“, ИТН и БСП, и това да е по-важно от правителството.

Ако Борисов желаеше правителството да падне, ГЕРБ щяха да участват в гласуването, но те не искат – искат си такса спокойствие от ПП–ДБ. До насрочения пети опит за гласуване на вота на недоверие в сряда, 22 ноември, има няколко дни за договаряне с лидерите на ПП–ДБ.

А Пеевски какво – страхува ли ги…?

За употребата на свободата: Нов европейски музей

Post Syndicated from Нева Мичева original https://www.toest.bg/za-upotrebata-na-svobodata-nov-evropeyski-muzey/

За употребата на свободата: Нов европейски музей

В края на октомври в центъра на Барселона отвори врати изложбено пространство без аналог в света – Музей на забраненото изкуство. На два етажа в елегантната стара къща, намираща се на крачка от преливащия от туристи булевард „Паседж де Грасия“, на първо време са подредени 42 творби от частната колекция на журналиста и предприемач Жузеп Мария (Тачо) Бенет. Колекцията датира от неотдавна, но вече наброява

над 200 „цензурирани, забранени или заклеймени по политически, социални или религиозни причини“ работи.

Всичко започва през 2018 г., когато международното изложение за съвременно изкуство ARCO в Мадрид сваля вече обявената инсталация „Политически затворници в Испания“ на Сантяго Сиера – 24 черно-бели фотографии на хора, попаднали под ударите на испанските закони заради убежденията си (въпреки че лицата са пикселирани, сред тях лесно се разпознават и няколко радетели на каталунската независимост). Каталунецът Бенет купува произведението и започва да го показва из страната. После се разравя в интернет, научава за други атакувани по света творби и придобива и някои от тях – отначало без намерение да прави сбирка, а просто защото така „се чувства добър човек“.

Фокус върху зачеркнатото

„Политическите затворници“ на Сиера не влизат в първата подборка на барселонския „експериментален музей“, но импулсът зад съдържанието му в момента е сходен: реакция на реакцията, връщане на премахнатото, светлина зад дръпнатите завеси. Всеки от разяснителните текстове към 42-та експоната носи в горната си част вестникарско заглавие, свързано със съответната полемика („Изкуството на затворниците от Гуантанамо се сблъсква с цензурата на Пентагона“; „С викове „Не на обратните!“ тълпа нахлува в Музея за изящни изкуства, удря и заплашва платно, изобразяващо феминизиран Сапата“ и пр.)

Неизбежната донякъде статика в пространството, заето с предмети на изкуството, е успешно разчупена с видеоматериали – протести за и срещу артисти; свидетелства на автори, засегнати от нечий официален или неофициален, но агресивен контрол. По думите на директорката на музея Роса Родриго (с десетилетен опит от мадридския „Кралица София“), идеята е акцентът да пада върху произведения, „откъснати [насила] от диалога с обществото, който е основната цел на изкуството“. И действително – макар изкушението да се наблегне на вече състояли се скандали да е голямо, кураторите са оставили луфт за самостоятелни бъдещи преживявания: взаимодействието на посетителите с творбите е нееднакво; срещата между неравните таланти и идеи на авторите и специфичния багаж на гледащите ги предизвиква интересна игра на културни и лични граници.

Най-старите експонати са 15 „прищевки“ на Гоя от ХVIII в. (плюс една гола жена на Климт и няколко еротични сцени на Пикасо за цвят), но повечето са от новото хилядолетие и на фона им дори уличните артисти Кийт Харинг (с една неозаглавена рисунка) и Банкси (с „Веселото ченге“) стоят като признати класици. Първото произведение, разположено още на входа на музея, е сив таен агент от папиемаше, седнал срещу влизащите и шпиониращ ги през тъмните си очила. „Зрител на зрителите“ (1972) на валенсианските дисиденти Екип „Хроника“ е смешен и страшен като истинските арбитри на правилността – хем нелепи, хем опасни.

„Би трябвало жените да ги зашиват,

свят без майки“, се казва на едно място в „Машината Хамлет“. Скоро след тази реплика на сцената излизат „три голи жени: Маркс, Ленин и Мао“. Налудничаво е, но чета пиесата на Хайнер Мюлер точно преди да посетя музея, а вътре виждам: една съшита жена, една раздрана жена, един гримиран Мао.

Съшитата жена е Evermust („вечно длъжна“) на Зоя Фалкова от Казахстан: по тертипа на Everlast, марка за боксово оборудване, Фалкова шие боксова круша с формите на женски торс в червено и черно. Първият отклик на този явен коментар върху домашното насилие е на първата феминистка изложба в Киргизстан през 2019-та. Деца се опитват да се гушнат в майчинската солидност на коженото тяло, мъже посягат да го ударят, а един големец директно го забранява:

Днес, 3 декември, министърът на културата А. Жаманкулов посети музея за изящни изкуства „Гапар Айтиев“, разгледа феминалето и назова работите, които следва да се отстранят,

пишат в местната преса. Малко след вернисажа директорката на музея е принудена да подаде оставка, а три седмици по-късно кураторката е пребита от двама мъже на улицата…

Раздраната жена е в „С цветя за Мария“ на Чаро Коралес, която – дали с голите си крака, дали с дланта между тях, дали с факта, че художничката си е направила автопортрет в синия плащ на Богородица – дотолкова засяга чувствата на млад испанец, че той влиза в залата, където е изложена картината, и я разпорва.

Изумително е колко ненавист към женското (от очертанията през сексуалността до всички атрибути на социалната роля) битува в съвремието и колко ясно си проличава тя в малтретирането на определени творби.

Едно от най-въздействащите места в Музея на забраненото изкуство е и едно от най-тихите, пред многократно цензурираната „Статуя на мира“ на Ким Сеокюн и Ким Юнсан. Два стола – на единия седи примерно девойче с миловидно лице, на другия си поканен да седнеш ти. Девойчето е обобщение на сексуалните робини на японската армия по време на Втората световна война. Частите му са символи: надигнатите петички (нестабилността), птичето на рамото (мирът и освобождението), свитите юмруци (нежеланието на оцелелите жертви – корейки, китайки, филипинки – да мълчат и да бъдат отпращани с половинчати извинения)…

Народът е малолетен, градът е болен

В шедьовъра на Елио Петри „Разследване на един гражданин извън всяко подозрение“ героят от заглавието на филма е и полицай, и търсен от полицията убиец. Най-притеснителното му качество обаче е не жестокостта, а убедеността в правото да упражнява власт над плебса.

Употребата на свободата застрашава отвсякъде традиционния строй и установените власти –

казва той в една своя реч пред колеги; – 

употребата на свободата предразполага всеки гражданин да се превърне в съдник, което ни пречи да изпълняваме свободно свещените си функции. Ние пазим закона и го искаме непроменен, издялан във времето. Народът е малолетен, градът е болен. На други се полага да лекуват и да образоват, а на нас – дългът да възпираме. Репресията е нашата ваксина! Репресията е култура!

Неизбежно си спомням за този цинизъм в залите на барселонския музей, събрали истории, в които пулсира същата лудост: убийствената страст на индивиди и институции да властват над презрените други и необходимостта на другите да се опълчват. Темите кръжат около светски и религиозни диктатури; желанията за бунт и скъсване са срещу неизменчиви модели, от които се възползва само малка върхушка.

Неслучайно разпятията са най-честият мотив.

В Музея те са четири и не е за вярване колко различни са пътищата, които са извървели и по които отвеждат. Piss Christ (1987) на работещия с телесни течности американец Андрес Серано е красив Христос на кръста в мътно червено и жълто, който, разбираме миг по-късно, е фотография на пластмасова фигурка, потопена в урината на автора. Финландецът Яни Лейнонен е разпнал на кръста изпосталелия клоун Роналд Макдоналд (кураторите съобразително са го „вързали“ с огромното голо тяло в „Макдоналдс“ от видеото на Йошуа Окон „Картофки на свободата: натюрморт“), а британецът Тери О’Нийл – Ракел Уелч в оскъдно облекло. Най-понятен сякаш е Христосът на самоукия аржентинец Леон Ферари от „Западната и християнска цивилизация“, прикован върху американски изтребител (творбата е класическа критика на милитаризма от времето на нашествието във Виетнам).

„Амин“ на Абел Аскона е надпис от 242 просфори, „заети“ от съответния брой реални комкания. Надписът гласи PEDERASTIA (значението на испанската дума съответства на българското „педофилия“ – „сексуално влечение/злоупотреба спрямо деца“) и предизвиква брутален отпор от Католическата църква, какъвто чудовищните ѝ издевателства над стотици хиляди деца никога не е имал. Аскона е съден многократно (вж. триметровото му произведение, наречено „Кулата“ и състоящо се от документи по делата, водени срещу него) и му се налага да емигрира от родната си Испания в Португалия.

Там емигрант е и Ай Уейуей, представен в музея с „Филипо Строци от лего“ – когато през 2015 г. в „Лего“ научават, че китайският артист се кани с поредната си огромна поръчка да прави политическа инсталация, отказват да му продадат нужните „тухлички“ и се налага той да ги събере от лего запасите на своите почитатели и с покупка на китайски имитации на датските конструктори. (Детайл от последната минута: току-що четири изложби на Ай Уейуей в различни градове бяха отменени заради негов туит.)

Цензурата понякога е самоналожена, а понякога предизвиква толкова силен обратен ефект, че чак можем да си я пожелаем. Инсталацията „Червено-синьо мълчание“ на Зулиха Буабдела е „комплимент към силните жени в арабския свят“ и представлява 30 мюсюлмански молитвени килимчета с по чифт лъскави женски обувки върху всяко. Буабдела сама я оттегля малко след нападението в редакцията на „Шарли Ебдо“…

Късометражката на Наталия ЛЛ от 70-те „Консуматорско изкуство“ показва симпатична млада жена, която съблазнително облизва наденички, банани, пръстите си. През 2019 г. видеото е изложено, а после и махнато от Националната художествена галерия в Полша, което вдига цунами в социалните мрежи, бързо залети от селфита на хора, ядящи банани…

От музея няма как да отсъства нашият национален приятел – чехът Давид Черни, и неговата „Акула“ е един от най-смущаващите експонати – жесток реприз на прочутата акула във формалдехид на Деймиън Хърст. Тук в центъра на огромен „аквариум“ обаче плува не животно, а владетел: скулптура на Саддам Хюсеин във финалните му мигове – разрошен, оголен, завързан, беззащитен.

Впрочем именно „Животното и владетелят“ (по Дерида) е надсловът на изложбата в барселонския MACBA, от която преди няколко години спешно е изключена Not Dressed for Conquering/Haute Couture 04 Transport на австрийката Инес Дуяк – скулптурна група от папиемаше, в която радостен вълк обладава боливийска синдикалистка, която на свой ред обладава бившия крал на Испания Хуан Карлос I, повръщащ зелена растителност върху германски каски. Докато вилнеенето над безкрайно компрометирания монарх ми е някак разбираемо, това над смелата Домитила Чунгара, изтезавана за възгледите си и починала от рак, ме обърква и се налага да търся информация извън музея (едно от големите му предимства – дава хляб за размисъл и отваря апетит за още).

Превратното тълкуване и вулгарният редукционизъм са все по-обичайни форми на цензура в Европа,

започва Дуяк един свой прелюбопитен текст по въпроса, в който обяснява, че творбата ѝ се занимава с късата памет на неолиберализма и с връзките между европейския нацизъм и Латинска Америка, между модата и колониализма.

Съдници в мрака

Един от най-разпространените кошмари е да се видиш насън гол, изтъпанен пред хора, които те гледат и преценяват – все едно дали случайни минувачи, роднини, или изпитни комисии. Любопитното в един музей, обусловен от активната намеса в чуждите работи, е, че докато съди съдещите (избира определени творби и ги излага напук на опита да бъдат потулени, което вече е позиция), те заставя да реагираш колкото на експонатите, толкова и на евентуалната си негативност към някои от тях. Хвърля те гол пред собствения ти вътрешен трибунал, който те обсипва с коварни въпроси.

Какво е редно и нередно в изкуството и съвпада ли то с редното и нередното извън него?

Ако някое произведение ме отблъсква до степен да си мисля, че съществуването му е излишно, лош човек ли съм? Който вижда в еротичното „Портфолио Х“ на Мейпълторп повече насилие, отколкото поезия, дребен невежа ли е на фона на историческата фигура на автора? Защо е проблем да отхвърлиш като неадекватен плаката с тореадор, рисуван за тенис шампионата „Ролан Гарос“ от Микел Барсело? Ако определена група не иска да те чува и вижда, ще рече ли непременно, че си прав или имаш нещо смислено за (по)казване? Ако си прав, ще рече ли, че ще съумееш да се изразиш? Действително ли артистът трябва да е активист, както казва Зулиха Буабдела?

Музеят на забраненото изкуство в Барселона дава възможност за тези и други въпроси, за някои отговори (има образователна програма за по-младите), както и за много обсъждания насън и наяве, на глас и наум.

Научни новини: Слънчогледи, динозаври, астероиди и резултати от проучвания

Post Syndicated from Михаил Ангелов original https://www.toest.bg/nauchni-novini-slunchogledi-dinozavri-rezultati-ot-prouchvaniya/

Какво гледат слънчогледите

Научни новини: Слънчогледи, динозаври, астероиди и резултати от проучвания

Фототропизмът (растеж по посока на светлината) е механизъм, който се среща при повечето растения и е добре проучен. Основни за функцията му са специални молекули, наречени фототропини, които са чувствителни към светлина в синята част на спектъра. Те насочват растежните хормони към тази страна на растението, която е в сянка, и тя расте по-бързо. Това кара растението да се наклони на другата страна и така се насочва към светлината. 

Хелиотропизмът при слънчогледите (следенето на слънцето) е сходен и познат на всички феномен – сутрин питите се обръщат на изток, за да посрещнат слънцето, а през деня плавно се накланят на запад, към залеза. В началото на годината беше описано наличието на вътрешен часовник, който казва на слънчогледите, че изгревът наближава и е време да се обърнат и да отворят цветчетата си в очакване на насекомите, които ще ги опрашат. Но това е само част от процеса.

До момента се смяташе, че движението на растенията също е базирано на фототропини, което може да се окаже невярно. Това сочи нова публикация, която сравнява генната експресия при слънчогледи, отгледани в специализирани растежни стаи и на полето. В растежните камери те не се движат през деня, а растат директно към неподвижния светлинен източник, при което се активират само гени, свързани с фототропизма, докато в слънчогледите на полето се наблюдава експресия на напълно различни гени.

За да разберат дали спектърът на светлината има значение за хелиотропизма, учените са поставили специални засенчващи филтри над растенията, които спират само определена част от спектъра. Това не е повлияло на движението на питите, което най-вероятно значи, че процесът се базира на множество механизми, действащи в синхрон и активирани от различни дължини на вълната.

Въпреки че не дава отговор как точно работи механизмът за насочване към слънцето, публикацията показва, че процесът е по-сложен, отколкото се смяташе до момента, и описва нови начини, по които растенията реагират на светлината. Статията е интересна и защото от нея се вижда ефектът на контролираните условия – невинаги между полученото в лабораторията и реалните условия може да се направи паралел.

Следа в изчезването на динозаврите

Изчезването на динозаврите вследствие на сблъсък на гигантски метеорит със Земята преди около 66 млн. години е добре приета хипотеза. Тя е предложена през 1980 г. от геолога Уолтър Алварес и баща му, носителя на Нобелова награда за физика Луис Уолтър Алварес, заради което е наричана и хипотеза на Алварес.

Всички доказателства, налични към момента, сочат, че мястото на удара е 180-километровият кратер Чиксулуб, намиращ се в днешен Юкатан, Мексико, който тогава е бил плитко море с дълбочина от няколкостотин метра. Най-вероятно астероидът е бил с диаметър между 10 и 15 км, сходен по големина с по-малкия спътник на Марс – Деймос. Освен експлозия и огромни приливни вълни, ударът му бързо е предизвикал рязко понижаване на температурата, което е довело до измирането на мегафауната. Смята се, че вследствие на това са загинали около 75% от всички видове на планетата, като най-засегнати са били по-големите животни, особено тревопасните и хищниците.

Причината за спадането на температурите все още е обект на дебати. Една от водещите хипотези до момента беше, че изгарянето на частици в атмосферата е довело до многократно увеличение на концентрацията на серен диоксид в нея. Комбинацията със саждите от пожарите по цялата планета е довела до рязко намаляване на количеството слънчева светлина, което е понижило температурата. Възможно е обаче основната причина за тъмната зима, покрила Земята, да се окаже друга – фин прах, изхвърлен при удара.

Това показват резултатите от измерването на силикатни частици, отложени в находището „Танис“ в Северна Дакота. С помощта на лазернодифракционен апарат размерът на частиците е определен между 0,8 и 8 µм – многократно по-малък от предполагания до момента. Това е от значение както за разпространението им в атмосферата, така и за взаимодействието им със слънчевата светлина. Най-вероятно те са били и основният компонент на материала, изхвърлен от удара.

След въвеждането на тези данни в климатична симулация се установява, че частици с такъв размер могат да се задържат във въздуха около 15 години и в зависимост от сезона да понижат глобалната температура с 15–19°C. В комбинация със серния диоксид и саждите моделът е показал потенциал за спад с до 25°C, като най-вероятно температурите са се задържали по-ниски от тези преди удара в продължение на поне 20 години.

Според модела запрашването на въздуха е довело и до пълно спиране на фотосинтетичните процеси, като това най-вероятно е станало само в рамките на две седмици, причинявайки колапс на хранителните вериги. Кризата е продължила почти две години, а възстановяването е започнало от Южното полукълбо, което се доказва от по-малкия брой изчезнали видове там. 

Работата на палеоклиматолозите е трудна, тъй като нямат пряк поглед върху промените и трябва да правят изводите си въз основа на косвени доказателства. Но откритията им за предишни масови измирания и драстични промени в климата са важни, защото могат да ни помогнат да разберем по-добре процесите, протичащи в момента.

Борба с астероиди

Съдбата на динозаврите служи за напомняне, че опасността от подобни събития е реална, макар и малко вероятна. Само преди няколко месеца покрай Земята премина астероид 2023 NT1 с диаметър между 30 и 60 м. Той е прелетял изключително близо, на по-малко от 100 000 км от нас, което е около четвърт от разстоянието до Луната. Въпреки че не би причинил глобална катастрофа, размерът му е достатъчен да унищожи голям град при директен удар. Най-притеснителното е, че следенето на подобни по-малки обекти е трудно – 2023 NT1 е забелязан два дни след като е преминал покрай Земята. Той ще посети Слънчевата система отново през 2044 г., но този път на повече от 1 AU (разстоянието до Слънцето, или 150 млн. км), поради което е премахнат от списъка с потенциално опасни обекти.

Най-доброто решение за опасни астероиди е отклоняването им в нова траектория, която ги отдалечава от Земята. Но това е възможно само ако има достатъчно време. В случай че обектът бъде открит само дни преди сблъсъка, единственото решение е раздробяването му на малки парчета, които или ще подминат планетата, или ще изгорят в атмосферата. Въпреки че звучи като филмов сценарий, е научно издържано.

Това показват доводите, изложени от американски учени в скорошна публикация, предизвикана от преминаването на 2023 NT1. Според тях ракета, която е подготвена да бъде изстреляна в рамките на няколко часа, може да се използва за фрагментиране на астероида. Вариантите са да се действа с пасивни (кинетични) импактори, освободени под формата на облак към астероида, или с активни (експлозивни) импактори – това най-вероятно ще се наложи за някои по-плътни астероиди.

Ако астероидът е от камък (или агрегати), симулациите показват, че той може да бъде обезвреден с разбиване само ден преди удара, като е най-добре фрагментите да са поне 1000, за да може да се намалят ефектите върху атмосферата и да няма щети на повърхността на Земята. При плътни метални астероиди парчетата трябва да с по-малък размер и по-разпръснати, за да се избегне припокриване при изгарянето им.

Отклоняването на астероид с размерите на 2023 NT1 също е възможно и за това ще е нужен само кинетичен импактор с тегло 100 кг, но той трябва да бъде изстрелян няколко дни преди удара. Затова учените смятат, че при предупреждение от около седмица фрагментацията е по-подходящ метод. Тези симулации се базират на данните от сондата DART на NASA, която се сблъска с астероида Диморфос.

Към момента повечето програми за наблюдение и ранно известяване са американски с европейско партньорство. Поради това е най-вероятно и първите противоастероидни ракети да бъдат разработени там. Въпреки това, ако времето за реакция е кратко, местоположението за изстрелване на ракетата може да се окаже ключово, което предполага разполагането на подобен арсенал равномерно по цялата планета. Доколко това е възможно, е въпрос, на който по-скоро трябва да отговорят политиците. Учените показват, че имат решение, което е много вероятно да проработи.

Възпроизводимост в науката

Понякога и в контролирани условия е невъзможно да се повторят конкретни резултати. Тази тема се дискутира активно от дълго време, като се започне от областта на психологията, където е въведен терминът криза на възпроизводимостта. Основната причина са ограничените финансови средства, отпускани за изследвания, чиято цел е да повторят публикувани вече резултати.

В повечето случаи се разчита на изготвянето на проекти със силна „история“, а данните понякога остават на второ място. Донякъде това се дължи на натиска за постоянно публикуване, на който са подложени учените, а отрицателните резултати се приемат изключително трудно от научните издания. Но след като изследванията са вече публикувани, е много трудно да бъдат оборени и тъй като често става въпрос за репутация и его, възниква напрежение между авторите на първоначалните статии и тези, които не могат да повторят резултатите и да публикуват откритието си. Това води до погрешното впечатление, че единични изследвания са абсолютната истина по даден въпрос, а всъщност те са малка част от големия научен пъзел.

Ново проучване представя интересен поглед към проблема и показва колко важно е как ще бъдат обработени данните. То е достъпно в предпечатна версия и все още не е рецензирано, но с оглед на подхода към анализа заслужава да се обсъди, затова и редица публикации обърнаха внимание на представените резултати.

Авторите дават два набора данни на 146 учени в областта на екологията и еволюционната биология. Данните са свързани с два въпроса: доколко размерът на сините синигери се влияе от конкуренцията с другите малки в гнездото и дали тревната покривка пречи, или помага на евкалиптовите фиданки да прорастват. Получените 137 отговора (някои са работили в екип) са многозначителни.

Повечето от 74-те резултата, получени от първия набор данни, показват негативен ефект – колкото по-голяма е конкуренцията в гнездото, толкова по-малки са пиленцата. Но от тези 74 само половината смятат резултата за убедителен. Пет от отговорите са, че данните не показват ясна връзка между двата фактора. А според други пет конкуренцията в гнездото няма ефект. По-ярко разграничаване има при евкалиптовите фиданки. От 63 отговорили 6 откриват позитивен ефект от наличието на тревна покривка, 18 – негативен, а 8 не са сигурни в ефекта. Най-голямата група отговорили смята, че между двете няма връзка.

След получаването на резултатите те са дадени на трета група, която е симулирала рецензионния процес. При него резултатите, показващи най-голям ефект от тревната покривка върху евкалиптовите фиданки, са отхвърлени, но това не променя съществено анализа. При синигерите дори и най-крайните резултати са одобрени. Това показва колко голямо влияние имат подходът при обработка на данните и използваните статистически методи. Особено в биологията, където данните често са изключително хетерогенни, дори малки промени в анализа могат да доведат до абсолютно различен резултат. И въпреки че статиите преминават през рецензиране, това не е гаранция, че статистическият подход ще бъде оценен подобаващо.

Изследването е вдъхновено от друго проучване, при което на 29 екипа, работещи в областта на социалните науки, е даден набор от данни, свързан с цвета на кожата на футболисти и броя червени картони, които получават. Въпреки че 20 от групите откриват статистическа връзка между двете – медианата на вероятността тъмнокож играч да получи картон е около 1,3 пъти по-висока, – абсолютната им стойност варира в широки граници. И както авторите отбелязват, ако всеки един от тези 29 резултата се публикува като отделна статия, изводите може да са коренно различни – от пълна липса на връзка между двете до много силна, с вероятност почти три пъти по-висока в сравнение с играч със светла кожа.

Разпределената обработка на данните не е възможна винаги и крие своите рискове, така че най-вероятно ще остане по-рядко използван подход. Въпреки това, както отбелязват и авторите на изследването с футболните данни, е добра идея да се прилага, когато решенията засягат законодателни промени и други свързани процеси.

Но всичко това не трябва да се приема като сигнал, че науката не работи и не следва да се вярва на резултатите и експертите. Тази дискусия показва, че научният подход работи дори когато е приложен върху себе си. Основният извод за широката публика е, че единични изследвания не трябва да се приемат за абсолютен факт и не е лошо да сме мнителни към шокиращи заглавия в медиите. Това е особено важно при теми като здраве, хранене и икономика, в които сензационните новини не са рядкост.

Оптимистично за медицинските храни. Разговор с д-р Антоанета Тончева

Post Syndicated from Надежда Цекулова original https://www.toest.bg/meditsinski-hrani-dr-antoaneta-toncheva/

Оптимистично за медицинските храни. Разговор с д-р Антоанета Тончева

Д-р Антоанета Тончева е генетик – молекулярен биолог. Работила е 14 години в германски университетски детски болници, където прави докторантурата си и трупа постдокторантски опит. От 5 години е член на сдружение „Общност Мостове“. Тя е един от активистите, допринесли за осветляване на проблемите с достъпа до медицински храни в България.

Срещаме се с нея в последните дни на Международната седмица за повишаване на информираността за малнутрицията и скоро след като българските здравни власти след години публичен натиск най-после предприеха стъпки за заплащане на медицинските храни с публични средства.

Поводът да си говорим е продължаващото усилие медицинските храни, лечебните храни да станат част от портфолиото на Националната здравноосигурителна каса и да са достъпни за всички пациенти, които се нуждаят от тях. Относително добрата новина е, че може би от пролетта на следващата година това ще бъде факт. Но преди да стигнем до този момент, да тръгнем от въпроса защо Вие се занимавате с темата къде молекулярната биология се свързва с проблема с достъпа до медицински храни за българските пациенти?

Причините са и професионални, и лични. Всеки от нас, който е станал част от някакво движение, сдружение, неформална организация, пациентска или на хора с увреждания, е бил провокиран от пробойните в здравната и социалната система, често и от лични случки. В семейството си аз имам няколко души, които в последните 20 години са се нуждаели или се нуждаят в момента от специалните храни. Връзката с молекулярната биология и генетиката е, че редица редки заболявания, с каквито аз се занимавам, водят до невъзможност човек или да усвоява хранителните вещества (например едно такова заболяване е муковисцидозата), или пък до състояния, свързани с нисък мускулен тонус, до степен на невъзможност човек да преглъща и стомахът му да обработва храната – чисто физиологична невъзможност да се храни по обичайния начин. Също след онкологични заболявания, голяма част от които са тясно свързани с генетиката. Та това ме тласна да се занимавам с темата – поредицата от случаи, на които станах свидетел. Сред тях и на хора, които си отидоха от глад, не от заболяването си.

Да си представим, че част от хората, които ще прочетат този разговор, никога не са чували за проблема с достъпа до медицински храни. Затова да се върнем малко назад. Какво трябва да им разкажем? Вие споменахте някои от заболяванията, които може да доведат до недохранване, или малнутриция. Какво е това?

Малнутрицията е състояние, при което тялото системно не получава нужните му хранителни вещества. Тя може да се дължи на огромен набор от основни заболявания.

Може ли да ги групирате, за да дадем някаква представа на читателите?  

Заболяванията и състоянията са най-разнообразни. Най-честият пример, за който може би обикновеният читател ще се сети, са хората след инсулт. Те често са парализирани частично, в по-малка или по-голяма степен, дълго време се залежават, буквално изпосталяват. На английски този процес се нарича wasting, защото тялото изразходва много енергия с цел да се възстанови от уврежданията, настъпили вследствие на инсулта, и когато в такава ситуация човек няма достъп до пълния спектър от хранителни вещества, изразходва каквито подкожни мазнини има. В един момент се стига до толкова критично ниско тегло, че тялото започва да разгражда собствените си белтъци, един вид да „се самоизяжда“. Това може да се види при хора с хранителни разстройства, с генетични синдроми, при страдащи от парализа на стомаха или парализа на червата. Пациентите на активна химиотерапия са също пример за хора в такава нужда и страшно пренебрегвана група – тялото ти се бори с тумора, бори се с нежеланите ефекти от самите лекарства и така то изразходва много повече енергия, отколкото чисто физически може да приеме. Толкова са разнообразни тези състояния, че е трудно да се изброят. Но всеки от нас на практика е потенциален пациент, който може да има нужда за по-малко или повече време от медицинска храна.  

Медицинската храна за различните заболявания различава ли се?

Има различни варианти, да. Основната идея на медицинските храни е, че те са със специална формула, според която в малък обем се съдържа много енергия. Така изпиваш едно шишенце от, да кажем, 200 мл и това е равно на две пържоли, образно казано. Вече има храна и под формата на кремчета. Има и много концентрирани храни, които се вкарват с тръбичка в тялото през сонда или през стома. Те са вече за доста по-специфични състояния.

Знае ли се приблизително годишно колко души в България биха имали нужда от медицинска храна?

За съжаление, към днешна дата такива данни не се събират. Ако запитате Здравната каса, ще отговорят може би само за тези хора, които получават специални обеднени медицински храни. При тях липсва някакъв компонент, защото пациентите не могат да го преработват. Състояния, които изискват такова хранене, са, да кажем, фенилкетонурия и сродни вродени грешки на обмяната. Но никой никога не е опитвал да преброи пациентите с недохранване и критично ниско тегло.

Как са се хранили до момента (а и в момента) тези хора, между които и много деца?

С дарителски средства, кампании, дарени храни… Има активисти, които се занимават с набиране на средства и купуване на храни. Понякога компаниите вносителки даряват храни с изтичащ срок на годност. Когато съм в Германия аз, а и други българи в чужбина, купуваме оттам и пращаме, защото са по-евтини. Отделно от това семействата продават каквото имат за продаване – имоти, коли… Всичко това при тотално отсъствие на държавните здравни институции. Казано накратко – чрез волни пожертвования. Едно от децата от кампаниите ни – Веско, днес на 25 – от 22 години е със стома и семейството му се справя без никаква подкрепа.

Вие имате дългогодишна практика в друга система, за която сме свикнали да смятаме, че е доста по-хуманна към пациентите. Може ли да разкажете как е решен този въпрос в Германия?  

Системата е наистина драстично различна. Имам преки наблюдения върху пациенти с муковисцидоза, защото работих в детската клиника на Университетската болница в Регенсбург, където има център по муковисцидоза. Там съм и преводач на български пациенти и познавам случаите им в детайли. Всичко, което е необходимо за тези деца, включително витамините им, се изписва по каса – инхалаторът, резервните му части, всички видове изследвания, всички антибиотици за орален или венозен прием, т.нар. генни терапии за муковисцидоза също… И медицинските храни се изписват по този ред, когато са необходими. Те се назначават от диетолога в болницата, при когото пациентите минават задължително на консултация на всеки три или шест месеца, в зависимост от нуждата.

Познавам детенце с булозна епидермолиза, т.нар. пеперудена болест, при която кожата е много лесно ранима и при обикновен допир се получават сериозни рани. Тялото има нужда от много енергия, за да може оздравителните процеси в тази крехка кожа да вървят гладко и раните да зарастват. Това намалява болката, намалява и риска от тежки инфекции, които могат да бъдат дори смъртоносни. За това момиченце палиативният екип е изписал медицинска храна и тя пристига в кашонче на вратата на дома му. Не е нужно да се чака за протокол, да се лежи в болница, да се обикалят аптечни складове. При това дете медицинската храна се прилага като добавъчно хранене, то не е лишено от възможността да яде и нормална храна, какъвто понякога е случаят при други пациенти.

А в България какъв е процесът?

Тук няма нищо, но вече сме обнадеждени, че ще има, след едно решение на Здравната каса.

Как се стигна до това решение?

Проблемът с медицинските храни стои на масата от години. От 13, за да сме по-точни. Преди нашия разговор погледнах най-старата си кореспонденция. Това са едни препратени писма от майката на Веско, която през 2010 г. може би за първи път вдигна голям шум по темата. Веско е емблематична личност за нашата общност. Той е един много сладък младеж – вече младеж, преди 13 години е бил дете – с доста рядък генетичен синдром, който остава невидим по всички параграфи за българската здравна система. От 9 години никой не се е интересувал дали е жив. От тригодишен с гастростома. Неговият рядък генетичен синдром е направил така, че да не може да преглъща добре и в даден момент вече съвсем да не може. Това налага майка му да готви кашички, да ги пасира и да ги вкарват през гастростомата. Сега Веско е на 25 – сагата продължава от 22 години. Първото писмо, което майка му пази, а вероятно има и по-ранни, е от юни 2010-та. Написала го е до президента, до дарителски организации, до Здравната каса, до Министерството на здравеопазването…. Няколко месеца по-късно Министерството обещава, че ще дискутират проблема много подробно. Оттогава са минали 13 години.

Сега си спомних, че след това „Българската Коледа“ започна да плаща храните.

Да. „Българската Коледа“ започна да плаща някои от храните за някои от екзотичните метаболитни заболявания, но само за деца до 18 години. Това какво означава? Добутал си ги живи и колкото е възможно здрави до 18, после оставяме семействата да се оправят. Довиждане.

Но да се върнем на тази сага, която се точи над 13 години, само нашето сдружение работи по нея над 5. В целия този промеждутък от време сме наясно, че са нужни данни, за да можем да изпълним всички критерии на списъците, наредбите и другите подзаконови нормативни актове. Никой обаче не започна да събира данни. И до ден днешен не е ясно колко са хората с малнутриция. След поредица от разговори, писма до здравни комисии, срещи с депутати, акции в Народното събрание с картини, рисувани от деца с увреждания, пускане на картички в пощенските кутии на депутатите и прочее те така и не ни обърнаха внимание. Докато не обединихме усилия с Националната мрежа за децата и още над 20 организации, които да ни подкрепят, и не започнахме системно да се развяваме по медиите, с извинение за грубия израз, за да се забележи проблемът с недохранването и липсата на медицински храни.  

Най-накрая през 2022 г. се сформира работна група. Бяхме включени трима души от НПО сектора – аз, Аделина Банакиева от сдружение „Общност Мостове“ и Антоанета Иванова от НМД. Уведомиха ни за първото заседание на тази група три часа преди провеждането му. Това беше отношението на институциите към процеса и към нас.

В крайна сметка ние сами събрахме подкрепа от лекари, направихме списък на Министерството на здравеопазването от кои експертни съвети по специалности да поискат становища. Седем експертни съвета бяха попитани, тези по онкология и онкохематологични заболявания не пожелаха да отговорят. Дълго време ведомството отказваше да ни даде становищата, за да видим какво пише в тях.

Минаха месеци, докато получим всички документи и разберем, че част от експертните съвети са дали негативни становища. На една от срещите представители на НЗОК си позволиха да ни заплашват, че ако не се съгласим да приемем НЗОК да включи в списъка си само три заболявания, за които да започне да плаща храна, няма да видим медицински храни за никого още десет години. Стана медиен скандал, после отново имаше затишие, избори, смяна на хора на ръководни позиции.

На поредна среща след още месеци ние отново настояхме, че единственото решение, което ще приемем, е малнутрицията да се впише в нормативната уредба като самостоятелно заболяване, за да може всички с този проблем, независимо от основната си диагноза, да имат право на храна. Обосновахме се с европейски данни и със становищата на лекарите, които ни подкрепят през цялото време.

След всичко разказано дотук ми се вижда важно да ги назовете. Кои са те?

Да, това са проф. Миглена Георгиева и проф. Ружа Панчева от Варна, доц. Янков от Университетската болница „Св. Георги“ в Пловдив, д-р Мила Байчева от СБАЛДБ „Проф. Иван Митев“ в София и проф. Красимир Антонов от УМБАЛ „Св. Иван Рилски“ в София. Те са неотлъчно до нас през цялото това време.

Историята стана доста дълга, но нека я довършим; близо сме до развръзката.

Съвсем близо. Така след още шест седмици мълчание, на 17 октомври, Надзорният съвет на НЗОК излезе с решение средно тежката и тежката форма на малнутриция да влязат в този заветен списък със заболявания, за които се заплащат терапии.

Какви са следващите стъпки?

Двете с Антоанета Иванова от НМД бяхме част от работната група, която изготви спецификация на храните, които Касата ще заплаща. Сега тази спецификация трябва да се приеме от Надзорния съвет на НЗОК, да се изготвят методическите указания как да се оцени дали даден пациент има нужда от медицинска храна, която, доколкото разбирам, ще се изписва с протокол. После ще се обявят обществени поръчки. Реално очакваме първите пациенти да започнат да получават храни не по-рано от 1 април 2024 г. След 13 години чакане обаче това е някакъв лъч надежда.

Имам един деликатен въпрос. Ако дори експерти от експертните съвети не смятат, че част от пациентите им биха имали нужда от медицински храни, кой и как ще обучи лекарите да припознаят състоянието малнутриция като част от своите ангажименти и да предписват правилно медицинските храни?

Наясно сме, че ще има нужда от обучения и че както при всички информационни кампании под шапката на МЗ, така и при тази ще се окаже, че вероятно Министерството ще има нужда от помощ, тоест ние ще трябва да си проведем обученията сами.

Кои са специалистите, които според вас най-често ще изписват тези храни? Защото германската практика, за която разказахте по-горе, засега е неприложима у нас. Каква би била работещата практика в български условия?

Всъщност гастроентеролозите и педиатрите, които сега ще изработят критериите, вероятно ще обърнат внимание на няколко биохимични параметъра, плюс индекса на телесната маса и основното заболяване, ако то е известно. На базата на тези критерии комисия от типа на ЛКК би следвало да направи оценка и да назначи официално храната, за да може да се издаде протокол и пациентът да си я получи.

А кой ще насочва към тази комисия?

За новата възможност трябва да бъдат информирани както общопрактикуващите лекари, така и лекуващите специалисти от други медицински направления. Но се опасявам, че без усилията на НПО сектора информационна кампания в нужния мащаб едва ли ще има.

Вие какво ще правите до 1 април?

Ще следим дали се правят нужните стъпки. Докато не видим с очите си първия пациент, който си взема храната по Здравна каса, и не се уверим, че този алгоритъм работи, няма да се откажем.

Аз съм оптимист, че въпросът с храните ще бъде решен.


В рубриката „Разговори за здравеопазването“ Надежда Цекулова кани своите събеседници да поговорят без клишета и празнодумие за проблемите и решенията, болката и оздравяването, медицината и политиката.

Road localisation in GrabMaps

Post Syndicated from Grab Tech original https://engineering.grab.com/road-localisation-grabmaps

Introduction

In 2022, Grab achieved self-sufficiency in its Geo services. As part of this transition, one crucial step was moving towards using an internally-developed map tailored specifically to the market in which Grab operates. Now that we have full control over the map layer, we can add more data to it or improve it according to the needs of the services running on top. One key aspect that this transition unlocked for us was the possibility of creating hyperlocal data at map level.

For instance, by determining the country to which a road belongs, we can now automatically infer the official language of that country and display the street name in that language. In another example, knowing the country for a specific road, we can automatically infer the driving side (left-handed or right-handed) leading to an improved navigation experience. Furthermore, this capability also enables us to efficiently handle various scenarios. For example, if we know that a road is part of a gated community, an area where our driver partners face restricted access, we can prevent the transit through that area.

These are just some examples of the possibilities from having full control over the map layer. By having an internal map, we can align our maps with specific markets and provide better experiences for our driver-partners and customers.

Background

For all these to be possible, we first needed to localise the roads inside the map. Our goal was to include hyperlocal data into the map, which refers to data that is specific to a certain area, such as a country, city, or even a smaller part of the city like a gated community. At the same time, we aimed to deliver our map with a high cadence, thus, we needed to find the right way to process this large amount of data while continuing to create maps in a cost-effective manner.

Solution

In the following sections of this article, we will use an extract from the Southeast Asia map to provide visual representations of the concepts discussed.

In Figure 1, Image 1 shows a visualisation of the road network, the roads belonging to this area. The coloured lines in Image 2 represent the borders identifying the countries in the same area. Overlapping the information from Image 1 and Image 2, we can extrapolate and say that the entire surface included in a certain border could have the same set of common properties as shown in Image 3. In Image 4, we then proceed with adding localised roads for each area.

Figure 1 – Map of Southeast Asia

For this to be possible, we have to find a way to localise each road and identify its associated country. Once this localisation process is complete, we can replicate all this information specific to a given border onto each individual road. This information includes details such as the country name, driving side, and official language. We can go even further and infer more information, and add hyperlocal data. For example, in Vietnam, we can automatically prevent motorcycle access on the motorways.

Assigning each road on the map to a specific area, such as a country, service area, or subdivision, presents a complex task. So, how can we efficiently accomplish this?

Implementation

The most straightforward approach would be to test the inclusion of each road into each area boundary, but that is easier said than done. With close to 30 million road segments in the Southeast Asia map and over 10 thousand areas, the computational cost of determining inclusion or intersection between a polyline and a polygon is expensive.

Our solution to this challenge involves replacing the expensive yet precise operation with a decent approximation. We introduce a proxy entity, the geohash, and we use it to approximate the areas and also to localise the roads.

We replace the geometrical inclusion with a series of simpler and less expensive operations. First, we conduct an inexpensive precomputation where we identify all the geohases that belong to a certain area or within a defined border. We then identify the geohashes to which the roads belong to. Finally, we use these precomputed values to assign roads to their respective areas. This process is also computationally inexpensive.

Given the large area we process, we leverage big data techniques to distribute the execution across multiple nodes and thus speed up the operation. We want to deliver the map daily and this is one of the many operations that are part of the map-making process.

What is a geohash?

To further understand our implementation we will first explain the geohash concept. A geohash is a unique identifier of a specific region on the Earth. The basic idea is that the Earth is divided into regions of user-defined size and each region is assigned a unique id, which is known as its geohash. For a given location on earth, the geohash algorithm converts its latitude and longitude into a string.

Geohashes uses a Base-32 alphabet encoding system comprising characters ranging from 0 to 9 and A to Z, excluding “A”, “I”, “L” and “O”. Imagine dividing the world into a grid with 32 cells. The first character in a geohash identifies the initial location of one of these 32 cells. Each of these cells are then further subdivided into 32 smaller cells.This subdivision process continues and refines to specific areas in the world. Adding characters to the geohash sub-divides a cell, effectively zooming in to a more detailed area.

The precision factor of the geohash determines the size of the cell. For instance, a precision factor of one creates a cell 5,000 km high and 5,000 km wide. A precision factor of six creates a cell 0.61km high and 1.22 km wide. Furthermore, a precision factor of nine creates a cell 4.77 m high and 4.77 m wide. It is important to note that cells are not always square and can have varying dimensions.

In Figure 2, we have exemplified a geohash 6 grid and its code is wsdt33.

Figure 2 – An example of geohash code wsdt33

Using less expensive operations

Calculating the inclusion of the roads inside a certain border is an expensive operation. However, quantifying the exact expense is challenging as it depends on several factors. One factor is the complexity of the border. Borders are usually irregular and very detailed, as they need to correctly reflect the actual border. The complexity of the road geometry is another factor that plays an important role as roads are not always straight lines.

Figure 3 – Roads to localise

Since this operation is expensive both in terms of cloud cost and time to run, we need to identify a cheaper and faster way that would yield similar results. Knowing that the complexity of the border lines is the cause of the problem, we tried using a different alternative, a rectangle. Calculating the inclusion of a polyline inside a rectangle is a cheaper operation.

Figure 4 – Roads inside a rectangle

So we transformed this large, one step operation, where we test each road segment for inclusion in a border, into a series of smaller operations where we perform the following steps:

  1. Identify all the geohashes that are part of a certain area or belong to a certain border. In this process we include additional areas to make sure that we cover the entire surface inside the border.
  2. For each road segment, we identify the list of geohashes that it belongs to. A road, depending on its length or depending on its shape, might belong to multiple geohashes.

In Figure 5, we identify that the road belongs to two geohashes and that the two geohashes are part of the border we use.

Figure 5 – Geohashes as proxy

Now, all we need to do is join the two data sets together. This kind of operation is a great candidate for a big data approach, as it allows us to run it in parallel and speed up the processing time.

Precision tradeoff

We mentioned earlier that, for the sake of argument, we replace precision with a decent approximation. Let’s now delve into the real tradeoff by adopting this approach.

The first thing that stands out with this approach is that we traded precision for cost. We are able to reduce the cost as this approach uses less hardware resources and computation time. However, this reduction in precision suffers, particularly for roads located near the borders as they might be wrongly classified.

Going back to the initial example, let’s take the case of the external road, on the left side of the area. As you can see in Figure 6, it is clear that the road does not belong to our border. But when we apply the geohash approach it gets included into the middle geohash.

Figure 6 – Wrong road localisation

Given that just a small part of the geohash falls inside the border, the entire geohash will be classified as belonging to that area, and, as a consequence, the road that belongs to that geohash will be wrongly localised and we’ll end up adding the wrong localisation information to that road. This is clearly a consequence of the precision tradeoff. So, how can we solve this?

Geohash precision

One option is to increase the geohash precision. By using smaller and smaller geohashes, we can better reflect the actual area. As we go deeper and we further split the geohash, we can accurately follow the border. However, a high geohash precision also equates to a computationally intensive operation bringing us back to our initial situation. Therefore, it is crucial to find the right balance between the geohash size and the complexity of operations.

Figure 7 – Geohash precision

Geohash coverage percentage

To find a balance between precision and data loss, we looked into calculating the geohash coverage percentage. For example, in Figure 8, the blue geohash is entirely within the border. Here we can say that it has a 100% geohash coverage.

Figure 8 – Geohash inside the border

However, take for example the geohash in Figure 9. It touches the border and has only around 80% of its surface inside the area. Given that most of its surface is within the border, we still can say that it belongs to the area.

Figure 9 – Geohash partially inside the border

Let’s look at another example. In Figure 10, only a small part of the geohash is within the border. We can say that the geohash coverage percentage here is around 5%. For these cases, it becomes difficult for us to determine whether the geohash does belong to the area. What would be a good tradeoff in this case?

Figure 10 – Geohash barely inside the border

Border shape

To go one step further, we can consider a mixed solution, where we use the border shape but only for the geohashes touching the border. This would still be an intensive computational operation but the number of roads located in these geohashes will be much smaller, so it is still a gain.

For the geohashes with full coverage inside the area, we’ll use the geohash for the localisation, the simpler operation. For the geohashes that are near the border, we’ll use a different approach. To increase the precision around the borders, we can cut the geohash following the border’s shape. Instead of having a rectangle, we’ll use a more complex shape which is still simpler than the initial border shape.

Figure 11 – Geohash following a border’s shape

Result

We began with a simple approach and we enhanced it to improve precision. This also increased the complexity of the operation. We then asked, what are the actual gains? Was it worthwhile to go through all this process? In this section, we put this to the test.

We first created a benchmark by taking a small sample of the data and ran the localisation process on a laptop. The sample comprised approximately 2% of the borders and 0.0014% of the roads. We ran the localisation process using two approaches.

  • With the first approach, we calculated the intersection between all the roads and borders. The entire operation took around 38 minutes.
  • For the second approach, we optimised the operation using geohashes. In this approach, the runtime was only 78 seconds (1.3 minutes).

However, it is important to note that this is not an apples-to-apples comparison. The operation that we measured was the localisation of the roads but we did not include the border filling operation where we fill the borders with geohashes. This is because this operation does not need to be run every time. It can be run once and reused multiple times.

Though not often required, it is still crucial to understand and consider the operation of precomputing areas and filling borders with geohashes. The precomputation process depends on several factors:

  • Number and shape of the borders – The more borders and the more complex the borders are, the longer the operation will take.
  • Geohash precision – How accurate do we need our localisation to be? The more accurate it needs to be, the longer it will take.
  • Hardware availability

Going back to our hypothesis, although this precomputation might be expensive, it is rarely run as the borders don’t change often and can be triggered only when needed. However, regular computation, where we find the area to which each road belongs to, is often run as the roads change constantly. In our system, we run this localisation for each map processing.

We can also further optimise this process by applying the opposite approach. Geohashes that have full coverage inside a border can be merged together into larger geohashes thus simplifying the computation inside the border. In the end, we can have a solution that is fully optimised for our needs with the best cost-to-performance ratio.

Figure 12 – Optimised geohashes

Conclusion

Although geohashes seem to be the right solution for this kind of problem, we also need to monitor their content. One consideration is the road density inside a geohash. For example, a geohash inside a city centre usually has a lot of roads while one in the countryside may have much less. We need to consider this aspect to have a balanced computation operation and take full advantage of the big data approach. In our case, we achieve this balance by considering the number of road kilometres within a geohash.

Figure 13 – Unbalanced data

Additionally, the resources that we choose also matter. To optimise time and cost, we need to find the right balance between the running time and resource cost. As shown in Figure 14, based on a sample data we ran, sometimes, we get the best result when using smaller machines.

Figure 14 – Cost vs runtime

The achievements and insights showcased in this article are indebted to the contributions made by Mihai Chintoanu. His expertise and collaborative efforts have profoundly enriched the content and findings presented herein.

Join us

Grab is the leading superapp platform in Southeast Asia, providing everyday services that matter to consumers. More than just a ride-hailing and food delivery app, Grab offers a wide range of on-demand services in the region, including mobility, food, package and grocery delivery services, mobile payments, and financial services across 428 cities in eight countries.

Powered by technology and driven by heart, our mission is to drive Southeast Asia forward by creating economic empowerment for everyone. If this mission speaks to you, join our team today!

Happy anniversary, Amazon CloudFront: 15 years of evolution and internet advancements

Post Syndicated from Danilo Poccia original https://aws.amazon.com/blogs/aws/happy-anniversary-amazon-cloudfront-15-years-of-evolution-and-internet-advancements/

I can’t believe it’s been 15 years since Amazon CloudFront was launched! When Amazon S3 became available in 2006, developers loved the flexibility and started to build a new kind of globally distributed applications where storage was not a bottleneck. These applications needed to be performant, reliable, and cost-efficient for every user on the planet. So in 2008 a small team (a “two-pizza team“) launched CloudFront in just 200 days. Jeff Barr hinted at the new and yet unnamed service in September and introduced CloudFront two months later.

Since the beginning, CloudFront has provided an easy way to distribute content to end users with low latency, high data transfer speeds, and no long-term commitments. What started as a simple cache for Amazon S3 quickly evolved into a fully featured content delivery network. Now CloudFront delivers applications at blazing speeds across the globe, supporting live sporting events such as NFL, Cricket World Cup, and FIFA World Cup.

At the same time, we also want to provide you with the best tools to secure applications. In 2015, we announced AWS WAF integration with CloudFront to provide fast and secure access control at the edge. Then, we focused on developing robust threat intelligence by combining signals across services. This threat intelligence integrates with CloudFront, adding AWS Shield to protect applications from common exploits and distributed denial of service (DDoS) attacks. For example, we recently detected an unusual spike in HTTP/2 requests to Amazon CloudFront. We quickly realized that CloudFront had automatically mitigated a new type of HTTP request flood DDoS event.

A lot also happens at lower levels than HTTP. For example, when you serve your application with CloudFront, all of the packets received by the application are inspected by a fully inline DDoS mitigation system which doesn’t introduce any observable latency. In this way, L3/L4 DDoS attacks against CloudFront distributions are mitigated in real time.

We also made under-the-hood improvements like s2n-tls (short for “signal to noise”), an open-source implementation of the TLS protocol that has been designed to be small and fast with simplicity as a priority. Another similar improvement is s2n-quic, an open-source QUIC protocol implementation written in Rust.

With CloudFront, you can also control access to content through a number of capabilities. You can restrict access to only authenticated viewers or, through geo-restriction capability, configure the specific geographic locations that can access content.

Security is always important, but not every organization has dedicated security experts on staff. To make robust security more accessible, CloudFront now includes built-in protections such as one-click web application firewall setup, security recommendations, and an intuitive security dashboard. With these integrated security features, teams can put critical safeguards in place without deep security expertise. Our goal is to empower all customers to easily implement security best practices.

Web applications delivery
During the past 15 years, web applications have become much more advanced and essential to end users. When CloudFront launched, our focus was helping deliver content stored in S3 buckets. Dynamic content was introduced to optimize web applications where portions of a website change for each user. Dynamic content also improves access to APIs that need to be delivered globally.

As applications become more distributed, we looked at ways to help developers make efficient use of its global footprint and resources at the edge. To allow customization and personalization of content close to end users and minimize latency, Lambda@Edge was introduced.

When fewer compute resources are needed, CloudFront Functions can run lightweight JavaScript functions across edge locations for low-latency HTTP manipulations and personalized content delivery. Recently, CloudFront Functions expanded to further customize responses, including modifying HTTP status codes and response bodies.

Today, CloudFront handles over 3 trillion HTTP requests daily and uses a global network of more than 600 points of presence and 13 Regional edge caches in more than 100 cities across 50 countries. This scale helps power the most demanding online events. For example, during the 2023 Amazon Prime Day, CloudFront handled peak loads of over 500 million HTTP requests per minute, totaling over 1 trillion HTTP requests.

Amazon CloudFront has more than 600,000 active developers building and delivering applications to end users. To help teams work at their full speed, CloudFront introduced continuous deployment so developers can test and validate configuration changes on a portion of traffic before full deployment.

Media and entertainment
It’s now common to stream music, movies, and TV series to our homes, but 15 years ago, renting DVDs was still the norm. Running streaming servers was technically complex, requiring long-term contracts to access the global infrastructure needed for high performance.

First, we added support for audio and video streaming capabilities using custom protocols since technical standards were still evolving. To handle large audiences and simplify cost-effective delivery of live events, CloudFront launched live HTTP streaming and, shortly after, improved support for both Flash-based (popular at the time) and Apple iOS devices.

As the media industry continued moving to internet-based delivery, AWS acquired Elemental, a pioneer in software-defined video solutions. Integrating Elemental offerings helped provide services, software, and appliances that efficiently and economically scale video infrastructures for use cases such as broadcast and content production.

The evolution of technologies and infrastructure allows for new ways of communication to become possible, such as when NASA did the first-ever live 4K stream from space using CloudFront.

Today, the world’s largest events and leading video platforms rely on CloudFront to deliver massive video catalogs and live stream content to millions. For example, CloudFront delivered streams for the FIFA World Cup 2022 on behalf of more than 19 major broadcasters globally. More recently, CloudFront handled over 120 Tbps of peak data transfer during one of the Thursday Night Football games of the NFL season on Prime Video and helped deliver the Cricket World Cup to millions of viewers across the globe.

What’s next?
Many things have changed during these 15 years but the focus on security, performance, and scalability stays the same. At AWS, it’s always Day 1, and the CloudFront team is constantly looking for ways to improve based on your feedback.

The rise of botnets is driving an ever-evolving, highly dynamic, and shifting threat landscape. Layer 7 DDoS attacks are becoming increasingly prevalent. The pervasiveness of bot traffic is increasing exponentially. As this occurs, we are evolving how we mitigate threats at the network border, at the edge, and in the Region, making it simpler for customers to configure the right security options.

Web applications are becoming more complex and interactive, and viewer expectations on latency and resiliency are even more stringent. This will drive new innovation. As new applications use generative artificial intelligence (AI), needs will evolve. These trends are will continue growing, so our investments will be focused on improving security and edge compute capabilities to support these new use cases.

With the current macroeconomic environment, many customers, especially small and medium-sized businesses and startups, look at how they can reduce their costs. Providing optimal price-performance has always been a priority for CloudFront. Cacheable data transferred to CloudFront edge locations from AWS resources does not incur additional fees. Also, 1 TB of data transfer from CloudFront to the internet per month is included in the free tier. CloudFront operates on a pay-as-you-go model with no upfront costs or minimum usage requirements. For more info, see CloudFront pricing.

As we approach AWS re:Invent, take note of these sessions that can help you learn about the latest innovations and connect with experts:

To learn more on how to speed up your websites and APIs and keep them protected, see the Application Security and Performance section of the AWS Developer Center.

Reduce latency and improve the security for your applications with Amazon CloudFront.

— Danilo

Power enterprise-grade Data Vaults with Amazon Redshift – Part 1

Post Syndicated from Asser Moustafa original https://aws.amazon.com/blogs/big-data/power-enterprise-grade-data-vaults-with-amazon-redshift-part-1/

Amazon Redshift is a popular cloud data warehouse, offering a fully managed cloud-based service that seamlessly integrates with an organization’s Amazon Simple Storage Service (Amazon S3) data lake, real-time streams, machine learning (ML) workflows, transactional workflows, and much more—all while providing up to 7.9x better price-performance than other cloud data warehouses.

As with all AWS services, Amazon Redshift is a customer-obsessed service that recognizes there isn’t a one-size-fits-all for customers when it comes to data models, which is why Amazon Redshift supports multiple data models such as Star Schemas, Snowflake Schemas and Data Vault. This post discusses best practices for designing enterprise-grade Data Vaults of varying scale using Amazon Redshift; the second post in this two-part series discusses the most pressing needs when designing an enterprise-grade Data Vault and how those needs are addressed by Amazon Redshift.

Whether it’s a desire to easily retain data lineage directly within the data warehouse, establish a source-system agnostic data model within the data warehouse, or more easily comply with GDPR regulations, customers that implement a Data Vault model will benefit from this post’s discussion of considerations, best practices, and Amazon Redshift features relevant to the building of enterprise-grade Data Vaults. Building a starter version of anything can often be straightforward, but building something with enterprise-grade scale, security, resiliency, and performance typically requires knowledge of and adherence to battle-tested best practices, and using the right tools and features in the right scenario.

Data Vault overview

Let’s first briefly review the core Data Vault premise and concepts. Data models provide a framework for how the data in a data warehouse should be organized into database tables. Amazon Redshift supports a number of data models, and some of the most popular data models include STAR schemas and Data Vault.

Data Vault is not only a modeling methodology, it’s also an opinionated framework that tells you how to solve certain problems in your data ecosystem. An opinionated framework provides a set of guidelines and conventions that developers are expected to follow, rather than leaving all decisions up to the developer. You can compare this with what big enterprise frameworks like Spring or Micronauts do when developing applications at enterprise scale. This is incredibly helpful especially on large data warehouse projects, because it structures your extract, load, and transform (ELT) pipeline and clearly tells you how to solve certain problems within the data and pipeline contexts. This also allows for a high degree of automation.

Data Vault 2.0 allows for the following:

  • Agile data warehouse development
  • Parallel data ingestion
  • A scalable approach to handle multiple data sources even on the same entity
  • A high level of automation
  • Historization
  • Full lineage support

However, Data Vault 2.0 also comes with costs, and there are use cases where it’s not a good fit, such as the following:

  • You only have a few data sources with no related or overlapping data (for example, a bank with a single core system)
  • You have simple reporting with infrequent changes
  • You have limited resources and knowledge of Data Vault

Data Vault typically organizes an organization’s data into a pipeline of four layers: staging, raw, business, and presentation. The staging layer represents data intake and light data transformations and enhancements that occur before the data comes to its more permanent resting place, the raw Data Vault (RDV).

The RDV holds the historized copy of all of the data from multiple source systems. It is referred to as raw because no filters or business transformations have occurred at this point except for storing the data in source system independent targets. The RDV organizes data into three key types of tables:

  • Hubs – This type of table represents a core business entity such as a customer. Each record in a hub table is married with metadata that identifies the record’s creation time, originating source system, and unique business key.
  • Links – This type of table defines a relationship between two or more hubs—for example, how the customer hub and order hub are to be joined.
  • Satellites – This type of table records the historized reference data about either hubs or links, such as product_info and customer_info

The RDV is used to feed data into the business Data Vault (BDV), which is responsible for reorganizing, denormalizing, and aggregating data for optimized consumption by the presentation mart. The presentation marts, also known as the data mart layer, further reorganizes the data for optimized consumption by downstream clients such as business dashboards. The presentation marts may, for example, reorganize data into a STAR schema.

For a more detailed overview of Data Vault along with a discussion of its applicability in the context of very interesting use cases, refer to the following:

How does Data Vault fit into a modern data architecture?

Currently, the lake house paradigm is becoming a major pattern in data warehouse design, even as part of a data mesh architecture. This follows the pattern of data lakes getting closer to what a data warehouse can do and vice versa. To compete with the flexibility of a data lake, Data Vault is a good choice. This way, the data warehouse doesn’t become a bottleneck and you can achieve similar agility, flexibility, scalability, and adaptability when ingestion and onboarding new data.

Platform flexibility

In this section, we discuss some recommended Redshift configurations for Data Vaults of varying scale. As mentioned earlier, the layers within a Data Vault platform are well known. We typically see a flow from the staging layer to the RDV, BDV, and finally presentation mart.

The Amazon Redshift is highly flexible in supporting both modest and large-scale Data Vaults, offering features like the following:

Modest vs. large-scale Data Vaults

Amazon Redshift is flexible in how you decide to structure these layers. For modest data vaults, a single Redshift warehouse with one database with multiple schemas will work just fine.

For large data vaults with more complex transformations, we would look at multiple warehouses, each with their own schema of mastered data representing one or more layer. The reason for using multiple warehouses is to take advantage of the Amazon Redshift architecture’s flexibility for implementing large-scale data vault implementations, such as using Redshift RA3 nodes and Redshift Serverless for separating the compute from the data storage layer and using Redshift data sharing to share the data between different Redshift warehouses. This enables you to scale the compute capacity independently at each layer depending on the processing complexity. The staging layer, for example, can be a layer within your data lake (Amazon S3 storage) or a schema within a Redshift database.

Using Amazon Aurora zero-ETL integrations with Amazon Redshift, you can create a data vault implementation with a staging layer in an Amazon Aurora database that will take care of real-time transaction processing and move the data to Amazon Redshift automatically for further processing in the Data Vault implementation without creating any complex ETL pipelines. This way, you can use Amazon Aurora for transactions and Amazon Redshift for analytics. Compute resources are isolated for the same data, and you’re using the most efficient tools to process it.

Large-scale Data Vaults

For larger Data Vaults platforms, concurrency and compute power become important to process both the loading of data and any business transformations. Amazon Redshift offers flexibility to increase compute capacity both horizontally via concurrency scaling and vertically via cluster resize and also via different architectures for each Data Vault layer.

Staging layer

You can create a data warehouse for the staging layer and perform hard business rules processing here, including calculation of hash keys, hash diffs, and addition of technical metadata columns. If data is not loaded 24/7, consider either pause/resume or a Redshift Serverless workgroup.

Raw Data Vault layer

For raw Data Vault (RDV), it’s recommended to either create one Redshift warehouse for the whole RDV or one Redshift warehouse for one or more subject areas within the RDV. For example, if the volume of data and number of normalized tables within the RDV for a particular subject area is large (either the raw data layer has so many tables that it runs out of maximum table limit on Amazon Redshift or the advantage of workload isolation within a single Redshift warehouse outweighs the overhead of performance and management), this subject area within the RDV can be run and mastered on its own Redshift warehouse.

The RDV is typically loaded 24/7 so a provisioned Redshift data warehouse may be most suitable here to take advantage of reserved instance pricing.

Business Data Vault layer

For creating a data warehouse for the business Data Vault (BDV) layer, this could be larger in size than the previous data warehouses due to the nature of the BDV processing, typically denormalization of data from a large number of source RDV tables.

Some customers run their BDV processing once a day, so a pause/resume window for Redshift provisioned cluster may be cost beneficial here. You can also run BDV processing on an Amazon Redshift Serverless warehouse which will automatically pause when workloads complete and resume when workloads start processing again.

Presentation Data Mart layer

For creating Redshift (provisioned or serverless) warehouses for one or more data marts, the schemas within these marts typically contain views or materialized views, so a Redshift data share will be set up between the data marts and the previous layers.

We need to ensure there is enough concurrency to cope with the increased read traffic at this level. This is achieved via multiple read only warehouses with a data share or the use of concurrency scaling to auto scale.

Example architectures

The following diagram illustrates an example platform for a modest Data Vault model.

The following diagram illustrates the architecture for a large-scale Data Vault model.

Data Vault data model guiding principles

In this section, we discuss some recommended design principles for joining and filtering table access within a Data Vault implementation. These guiding principles address different combinations of entity type access, but should be tested for suitability with each client’s particular use case.

Let’s begin with a brief refresher of table distribution styles in Amazon Redshift. There are four ways that a table’s data can be distributed among the different compute nodes in a Redshift cluster: ALL, KEY, EVEN, and AUTO.

The ALL distribution style ensures that a full copy of the table is maintained on each compute node to eliminate the need for inter-node network communication during workload runs. This distribution style is ideal for tables that are relatively small in size (such as fewer than 5 million rows) and don’t exhibit frequent changes.

The KEY distribution style uses a hash-based approach to persisting a table’s rows in the cluster. A distribution key column is defined to be one of the columns in the row, and the value of that column is hashed to determine on which compute node the row will be persisted. The current generation RA3 node type is built on the AWS Nitro System with managed storage that uses high performance SSDs for your hot data and Amazon S3 for your cold data, providing ease of use, cost-effective storage, and fast query performance. Managed storage means this mapping of row to compute node is more in terms of metadata and compute node ownership rather than the actual persistence. This distribution style is ideal for large tables that have well-known and frequent join patterns on the distribution key column.

The EVEN distribution style uses a round-robin approach to locating a table’s row. Simply put, table rows are cycled through the different compute nodes and when the last compute node in the cluster is reached, the cycle begins again with the next row being persisted to the first compute node in the cluster. This distribution style is ideal for large tables that exhibit frequent table scans.

Finally, the default table distribution style in Amazon Redshift is AUTO, which empowers Amazon Redshift to monitor how a table is used and change the table’s distribution style at any point in the table’s lifecycle for greater performance with workloads. However, you are also empowered to explicitly state a particular distribution style at any point in time if you have a good understanding of how the table will be used by workloads.

Hub and hub satellites

Hub and hub satellites are often joined together, so it’s best to co-locate these datasets based on the primary key of the hub, which will also be part of the compound key of each satellite. As mentioned earlier, for smaller volumes (typically fewer than 5–7 million rows) use the ALL distribution style and for larger volumes, use the KEY distribution style (with the _PK column as the distribution KEY column).

Link and link satellites

Link and link satellites are often joined together, so it’s best to co-locate these datasets based on the primary key of the link, which will also be part of the compound key of each link satellite. These typically involve larger data volumes, so look at a KEY distribution style (with the _PK column as the distribution KEY column).

Point in time and satellites

You may decide to denormalize key satellite attributes by adding them to point in time (PIT) tables with the goal of reducing or eliminating runtime joins. Because denormalization of data helps reduce or eliminate the need for runtime joins, denormalized PIT tables can be defined with an EVEN distribution style to optimize table scans.

However, if you decide not to denormalize, then smaller volumes should use the ALL distribution style and larger volumes should use the KEY distribution style (with the _PK column as the distribution KEY column). Also, be sure to define the business key column as a sort key on the PIT table for optimized filtering.

Bridge and link satellites

Similar to PIT tables, you may decide to denormalize key satellite attributes by adding them to bridge tables with the goal of reducing or eliminating runtime joins. Although denormalization of data helps reduce or eliminate the need for runtime joins, denormalized bridge tables are still typically larger in data volume and involved frequent joins, so the KEY distribution style (with the _PK column as the distribution KEY column) would be the recommended distribution style. Also, be sure to define the bridge of the dominant business key columns as sort keys for optimized filtering.

KPI and reporting

KPI and reporting tables are designed to meet the specific needs of each customer, so flexibility on their structure is key here. These are often standalone tables that exhibit multiple types of interactions, so the EVEN distribution style may be the best table distribution style to evenly spread the scan workloads.

Be sure to choose a sort key that is based on common WHERE clauses such as a date[time] element or a common business key. In addition, a time series table can be created for very large datasets that are always sliced on a time attribute to optimize workloads that typically interact with one slice of time. We discuss this subject in greater detail later in the post.

Non-functional design principles

In this section, we discuss potential additional data dimensions that are often created and married with business data to satisfy non-functional requirements. In the physical data model, these additional data dimensions take the form of technical columns added to each row to enable tracking of non-functional requirements. Many of these technical columns will be populated by the Data Vault framework. The following table lists some of the common technical columns, but you can extend the list as needed.

Column Name Applies to Table Description
LOAD_DTS All A timestamp recording of when this row was inserted. This is a primary key column for historized targets (links, satellites, reference), and a non-primary key column for transactional links and hubs.
BATCH_ID All A unique process ID identifying the run of the ETL code that populated the row.
JOB_NAME All The process name from the ETL framework. This may be a sub-process within a larger process.
SOURCE_SYSTEM_CD All The system from which this data was discovered.
HASH_DIFF Satellite A method in Data Vault of performing change data capture (CDC) changes.
RECORD_ID Satellite
Link
Reference
A unique identifier captured by the code framework for each row.
EFFECTIVE_DTS Link Business effective dates to record the business validity of the row. It’s set to the LOAD_DTS if no business date is present or needed.
DQ_AUDIT Satellite
Link
Reference
Warnings and errors found during staging for this row, tied to the RECORD_ID.

Advanced optimizations and guidelines

In this section, we discuss potential optimizations that can be deployed at the start or later on in the lifecycle of the Data Vault implementation.

Time series tables

Let’s begin with a brief refresher on time series tables as a pattern. Time series tables involve taking a large table and segmenting it into multiple identical tables that hold a time-bound portion of the rows in the original table. One common scenario is to divide a monolithic sales table into monthly or annual versions of the sales table (such as sales_jan,sales_feb, and so on). For example, let’s assume we want to maintain data for a rolling time period using a series of tables, as the following diagram illustrates.

With each new calendar quarter, we create a new table to hold the data for the new quarter and drop the oldest table in the series. Furthermore, if the table rows arrive in a naturally sorted order (such as sales date), then no work is needed to sort the table data, resulting in skipping the expensive VACUUM SORT operation on table.

Time series tables can help significantly optimize workloads that often need to scan these large tables but within a certain time range. Furthermore, by segmenting the data across tables that represent calendar quarters, we are able to drop aged data with a single DROP command. Had we tried to perform the same DELETE operation on a monolithic table design using the DELETE command, for example, it would have been a more expensive deletion operation that would have left the table in a suboptimal state requiring defragmentation and also saves to run a subsequent VACUUM process to reclaim space.

Should a workload ever need to query against the entire time range, you can use standard or materialized views using a UNION ALL operation within Amazon Redshift to easily stitch all the component tables back into the unified dataset. Materialized views can also be used to abstract the table segmentation from downstream users.

In the context of Data Vault, time series tables can be useful for archiving rows within satellites, PIT, and bridge tables that aren’t used often. Time series tables can then be used to distribute the remaining hot rows (rows that are either recently added or referenced often) with more aggressive table properties.

Conclusion

In this post, we discussed a number of areas ripe for optimization and automation to successfully implement a Data Vault 2.0 system at scale and the Amazon Redshift capabilities that you can use to satisfy the related requirements. There are many more Amazon Redshift capabilities and features that will surely come in handy, and we strongly encourage current and prospective customers to reach out to us or other AWS colleagues to delve deeper into Data Vault with Amazon Redshift.


About the Authors

Asser Moustafa is a Principal Analytics Specialist Solutions Architect at AWS based out of Dallas, Texas. He advises customers globally on their Amazon Redshift and data lake architectures, migrations, and visions—at all stages of the data ecosystem lifecycle—starting from the POC stage to actual production deployment and post-production growth.

Philipp Klose is a Global Solutions Architect at AWS based in Munich. He works with enterprise FSI customers and helps them solve business problems by architecting serverless platforms. In this free time, Philipp spends time with his family and enjoys every geek hobby possible.

Saman Irfan is a Specialist Solutions Architect at Amazon Web Services. She focuses on helping customers across various industries build scalable and high-performant analytics solutions. Outside of work, she enjoys spending time with her family, watching TV series, and learning new technologies.

Power enterprise-grade Data Vaults with Amazon Redshift – Part 2

Post Syndicated from Asser Moustafa original https://aws.amazon.com/blogs/big-data/power-enterprise-grade-data-vaults-with-amazon-redshift-part-2/

Amazon Redshift is a popular cloud data warehouse, offering a fully managed cloud-based service that seamlessly integrates with an organization’s Amazon Simple Storage Service (Amazon S3) data lake, real-time streams, machine learning (ML) workflows, transactional workflows, and much more—all while providing up to 7.9x better price-performance than any other cloud data warehouses.

As with all AWS services, Amazon Redshift is a customer-obsessed service that recognizes there isn’t a one-size-fits-all for customers when it comes to data models, which is why Amazon Redshift supports multiple data models such as Star Schemas, Snowflake Schemas and Data Vault. This post discusses the most pressing needs when designing an enterprise-grade Data Vault and how those needs are addressed by Amazon Redshift in particular and AWS cloud in general. The first post in this two-part series discusses best practices for designing enterprise-grade data vaults of varying scale using Amazon Redshift.

Whether it’s a desire to easily retain data lineage directly within the data warehouse, establish a source-system agnostic data model within the data warehouse, or more easily comply with GDPR regulations, customers that implement a data vault model will benefit from this post’s discussion of considerations, best practices, and Amazon Redshift features as well as the AWS cloud capabilities relevant to the building of enterprise-grade data vaults. Building a starter version of anything can often be straightforward, but building something with enterprise-grade scale, security, resiliency, and performance typically requires knowledge and adherence to battle-tested best practices, and using the right tools and features in the right scenario.

Data Vault overview

For a brief review of the core Data Vault premise and concepts, refer to the first post in this series.

In the following sections, we discuss the most common areas of consideration that are critical for Data Vault implementations at scale: data protection, performance and elasticity, analytical functionality, cost and resource management, availability, and scalability. Although these areas can also be critical areas of consideration for any data warehouse data model, in our experience, these areas present their own flavor and special needs to achieve data vault implementations at scale.

Data protection

Security is always priority-one at AWS, and we see the same attention to security every day with our customers. Data security has many layers and facets, ranging from encryption at rest and in transit to fine-grained access controls and more. In this section, we explore the most common data security needs within the raw and business data vaults and the Amazon Redshift features that help achieve those needs.

Data encryption

Amazon Redshift encrypts data in transit by default. With the click of a button, you can configure Amazon Redshift to encrypt data at rest at any point in a data warehouse’s lifecycle, as shown in the following screenshot.

You can use either AWS Key Management Service (AWS KMS) or Hardware Security Module (HSM) to perform encryption of data at rest. If you use AWS KMS, you can either use an AWS managed key or customer managed key. For more information, refer to Amazon Redshift database encryption.

You can also modify cluster encryption after cluster creation, as shown in the following screenshot.

Moreover, Amazon Redshift Serverless is encrypted by default.

Fine-grained access controls

When it comes to achieving fine-grained access controls at scale, Data Vaults typically need to use both static and dynamic access controls. You can use static access controls to restrict access to databases, tables, rows, and columns to explicit users, groups, or roles. With dynamic access controls, you can mask part or all portions of a data item, such as a column based on a user’s role or some other functional analysis of a user’s privileges.

Amazon Redshift has long supported static access controls through the GRANT and REVOKE commands for databases, schemas, and tables, at row level and column level. Amazon Redshift also supports row-level security, where you can further restrict access to particular rows of the visible columns, as well as role-based access control, which helps simplify the management of security privileges in Amazon Redshift.

In the following example, we demonstrate how you can use GRANT and REVOKE statements to implement static access control in Amazon Redshift.

  1. First, create a table and populate it with credit card values:
    -- Create the credit cards table
    
    CREATE TABLE credit_cards 
    ( customer_id INT, 
    is_fraud BOOLEAN, 
    credit_card TEXT);
    
    --populate the table with sample values
    
    INSERT INTO credit_cards 
    VALUES
    (100,'n', '453299ABCDEF4842'),
    (100,'y', '471600ABCDEF5888'),
    (102,'n', '524311ABCDEF2649'),
    (102,'y', '601172ABCDEF4675'),
    (102,'n', '601137ABCDEF9710'),
    (103,'n', '373611ABCDEF6352');
    

  2. Create the user user1 and check permissions for user1 on the credit_cards table. We use SET SESSION AUTHORIZATION to switch to user1 in the current session:
       -- Create user
    
       CREATE USER user1 WITH PASSWORD '1234Test!';
    
       -- Check access permissions for user1 on credit_cards table
       SET SESSION AUTHORIZATION user1; 
       SELECT * FROM credit_cards; -- This will return permission defined error
    

  3. Grant SELECT access on the credit_cards table to user1:
    RESET SESSION AUTHORIZATION;
     
    GRANT SELECT ON credit_cards TO user1;
    

  4. Verify access permissions on the table credit_cards for user1:
    SET SESSION AUTHORIZATION user1;
    
    SELECT * FROM credit_cards; -- Query will return rows
    RESET SESSION AUTHORIZATION;

Data obfuscation

Static access controls are often useful to establish hard boundaries (guardrails) of the user communities that should be able to access certain datasets (for example, only those users that are part of the marketing user group should be allowed access to marketing data). However, what if access controls need to restrict only partial aspects of a field, not the entire field? Amazon Redshift supports partial, full, or custom data masking of a field through dynamic data masking. Dynamic data masking enables you to protect sensitive data in your data warehouse. You can manipulate how Amazon Redshift shows sensitive data to the user at query time without transforming it in the database by using masking policies.

In the following example, we achieve a full redaction of credit card numbers at runtime using a masking policy on the previously used credit_cards table.

  1. Create a masking policy that fully masks the credit card number:
    CREATE MASKING POLICY mask_credit_card_full 
    WITH (credit_card VARCHAR(256)) 
    USING ('000000XXXX0000'::TEXT);

  2. Attach mask_credit_card_full to the credit_cards table as the default policy. Note that all users will see this masking policy unless a higher priority masking policy is attached to them or their role.
    ATTACH MASKING POLICY mask_credit_card_full 
    ON credit_cards(credit_card) TO PUBLIC;

  3. Users will see credit card information being masked when running the following query
    SELECT * FROM credit_cards;

Centralized security policies

You can achieve a great deal of scale by combining static and dynamic access controls to span a broad swath of user communities, datasets, and access scenarios. However, what about datasets that are shared across multiple Redshift warehouses, as might be done between raw data vaults and business data vaults? How can scale be achieved with access controls for a dataset that resides on one Redshift warehouse but is authorized for use across multiple Redshift warehouses using Amazon Redshift data sharing?

The integration of Amazon Redshift with AWS Lake Formation enables centrally managed access and permissions for data sharing. Amazon Redshift data sharing policies are established in Lake Formation and will be honored by all of your Redshift warehouses.

Performance

It is not uncommon for sub-second SLAs to be associated with data vault queries, particularly when interacting with the business vault and the data marts sitting atop the business vault. Amazon Redshift delivers on that needed performance through a number of mechanisms such as caching, automated data model optimization, and automated query rewrites.

The following are common performance requirements for Data Vault implementations at scale:

  • Query and table optimization in support of high-performance query throughput
  • High concurrency
  • High-performance string-based data processing

Amazon Redshift features and capabilities for performance

In this section, we discuss Amazon Redshift features and capabilities that address those performance requirements.

Caching

Amazon Redshift uses multiple layers of caching to deliver subsecond response times for repeat queries. Through Amazon Redshift in-memory result set caching and compilation caching, workloads ranging from dashboarding to visualization to business intelligence (BI) that run repeat queries experience a significant performance boost.

With in-memory result set caching, queries that have a cached result set and no changes to the underlying data return immediately and typically within milliseconds.

The current generation RA3 node type is built on the AWS Nitro System with managed storage that uses high performance SSDs for your hot data and Amazon S3 for your cold data, providing ease of use, cost-effective storage, and fast query performance. In short, managed storage means fast retrieval for your most frequently accessed data and automated/managed identification of hot data by Amazon Redshift.

The large majority of queries in a typical production data warehouse are repeat queries, and data warehouses with data vault implementations observe the same pattern. The most optimal run profile for a repeat query is one that avoids costly query runtime interpretation, which is why queries in Amazon Redshift are compiled during the first run and the compiled code is cached in a global cache, providing repeat queries a significant performance boost.

Materialized views

Pre-computing the result set for repeat queries is a powerful mechanism for boosting performance. The fact that it automatically refreshes to reflect the latest changes in the underlying data is yet another powerful pattern for boosting performance. For example, consider the denormalization queries that might be run on the raw data vault to populate the business vault. It’s quite possible that some less-active source systems will have exhibited little to no changes in the raw data vault since the last run. Avoiding the hit of rerunning the business data vault population queries from scratch in those cases could be a tremendous boost to performance. Redshift materialized views provide that exact functionality by storing the precomputed result set of their backing query.

Queries that are similar to the materialized view’s backing query don’t have to rerun the same logic each time, because they can pull records from the existing result set. Developers and analysts can choose to create materialized views after analyzing their workloads to determine which queries would benefit. Materialized views also support automatic query rewriting to have Amazon Redshift rewrite queries to use materialized views, as well as auto refreshing materialized views, where Amazon Redshift can automatically refresh materialized views with up-to-date data from its base tables.

Alternatively, the automated materialized views (AutoMV) feature provides the same performance benefits of user-created materialized views without the maintenance overhead because Amazon Redshift automatically creates the materialized views based on observed query patterns. Amazon Redshift continually monitors the workload using machine learning and then creates new materialized views when they are beneficial. AutoMV balances the costs of creating and keeping materialized views up to date against expected benefits to query latency. The system also monitors previously created AutoMVs and drops them when they are no longer beneficial. AutoMV behavior and capabilities are the same as user-created materialized views. They are refreshed automatically and incrementally, using the same criteria and restrictions.

Also, whether the materialized views are user-created or auto-generated, Amazon Redshift automatically rewrites queries, without users to change queries, to use materialized views when there is enough of a similarity between the query and the materialized view’s backing query.

Concurrency scaling

Amazon Redshift automatically and elastically scales query processing power to provide consistently fast performance for hundreds of concurrent queries. Concurrency scaling resources are added to your Redshift warehouse transparently in seconds, as concurrency increases, to process read/write queries without wait time. When workload demand subsides, Amazon Redshift automatically shuts down concurrency scaling resources to save you cost. You can continue to use your existing applications and BI tools without any changes.

Because Data Vault allows for highly concurrent data processing and is primarily run within Amazon Redshift, concurrency scaling is the recommended way to handle concurrent transformation operations. You should avoid operations that aren’t supported by concurrency scaling.

Concurrent ingestion

One of the key attractions of Data Vault 2.0 is its ability to support high-volume concurrent ingestion from multiple source systems into the data warehouse. Amazon Redshift provides a number of options for concurrent ingestion, including batch and streaming.

For batch- and microbatch-based ingestion, we suggest using the COPY command in conjunction with CSV format. CSV is well supported by concurrency scaling. In case your data is already on Amazon S3 but in Bigdata formats like ORC or Parquet, always consider the trade-off of converting the data to CSV vs. non-concurrent ingestion. You can also use workload management to prioritize non-concurrent ingestion jobs to keep the throughput high.

For low-latency workloads, we suggest using the native Amazon Redshift streaming capability or the Amazon Redshift Zero ETL capability in conjunction with Amazon Aurora. By using Aurora as a staging layer for the raw data, you can handle small increments of data efficiently and with high concurrency, and then use this data inside your Redshift data warehouse without any extract, transform, and load (ETL) processes. For stream ingestion, we suggest using the native streaming feature (Amazon Redshift streaming ingestion) and have a dedicated stream for ingesting each table. This might require a stream processing solution upfront, which splits the input stream into the respective elements like the hub and the satellite record.

String-optimized compression

The Data Vault 2.0 methodology often involves time-sensitive lookup queries against potentially very large satellite tables (in terms of row count) that have low-cardinality hash/string indexes. Low-cardinality indexes and very large tables tend to work against time-sensitive queries. Amazon Redshift, however, provides a specialized compression method for low-cardinality string-based indexes called BYTEDICT. Using BYTEDICT creates a dictionary of the low-cardinality string indexes that allow Amazon Redshift to reads the rows even in a compressed state, thereby significantly improving performance. You can manually select the BYTEDICT compression method for a column, or alternatively rely on Amazon Redshift automated table optimization facilities to select it for you.

Support of transactional data lake frameworks

Data Vault 2.0 is an insert-only framework. Therefore, reorganizing data to save money is a challenge you may face. Amazon Redshift integrates seamlessly with S3 data lakes allowing you to perform data lake queries in your S3 using standard SQL as you would with native tables. This way, you can outsource less frequently used satellites to your S3 data lake, which is cheaper than keeping it as a native table.

Modern transactional lake formats like Apache Iceberg are also an excellent option to store this data. They ensure transactional safety and therefore ensure that your audit trail, which is a fundamental feature of Data Vault, doesn’t break.

We also see customers using these frameworks as a mechanism to implement incremental loads. Apache Iceberg lets you query for the last state for a given point in time. You can use this mechanism to optimize merge operations while still making the data accessible from within Amazon Redshift.

Amazon Redshift data sharing performance considerations

For large-scale Data Vault implementation, one of the preferred design principals is to have a separate Redshift data warehouse for each layer (staging, raw Data Vault, business Data Vault, and presentation data mart). These layers have separate Redshift provisioned or serverless warehouses according to their storage and compute requirements and use Amazon Redshift data sharing to share the data between these layers without physically moving the data.

Amazon Redshift data sharing enables you to seamlessly share live data across multiple Redshift warehouses without any data movement. Because the data sharing feature serves as the backbone in implementing large-scale Data Vaults, it’s important to understand the performance of Amazon Redshift in this scenario.

In a data sharing architecture, we have producer and consumer Redshift warehouses. The producer warehouse shares the data objects to one or more consumer warehouse for read purposes only without having to copy the data.

Producer/consumer Redshift cluster performance dependency

From a performance perspective, the producer (provisioned or serverless) warehouse is not responsible for query performance running on the consumer (provisioned or serverless) warehouse and has zero impact in terms of performance or activity on the producer Redshift warehouse. It depends on the consumer Redshift warehouse compute capacity. The producer warehouse is only responsible for the shared data.

Result set caching on the consumer Redshift cluster

Amazon Redshift uses result set caching to speed up the retrieval of data when it knows that the data in the underlying table has not changed. In a data sharing architecture, Amazon Redshift also uses result set caching on the consumer Redshift warehouse. This is quite helpful for repeatable queries that commonly occur in a data warehousing environment.

Best practices for materialized views in Data Vault with Amazon Redshift data sharing

In Data Vault implementation, the presentation data mart layer typically contains views or materialized views. There are two possible routes to create materialized views for the presentation data mart layer. First, create the materialized views on the producer Redshift warehouse (business data vault layer) and share materialized views with the consumer Redshift warehouse (dedicated data marts). Alternatively, share the table objects directly from the business data vault layer to the presentation data mart layer and build the materialized view on the shared objects directly on the consumer Redshift warehouse.

The second option is recommended in this case, because it gives us the flexibility of creating customized materialized views of data on each consumer according to the specific use case and simplifies the management because each data mart user can create and manage materialized views on their own Redshift warehouse rather than be dependent on the producer warehouse.

Table distribution implications in Amazon Redshift data sharing

Table distribution style and how data is distributed across Amazon Redshift plays a significant role in query performance. In Amazon Redshift data sharing, the data is distributed on the producer Redshift warehouse according to the distribution style defined for table. When we associate the data via a data share to the consumer Redshift warehouse, it maps to the same disk block layout. Also, a bigger consumer Redshift warehouse will result in better query performance for queries running on it.

Concurrency scaling

Concurrency scaling is also supported on both producer and consumer Redshift warehouses for read and write operations.

Cost and resource management

Given that multiple source systems and users will interact heavily with the data vault data warehouse, it’s a prudent best practice to enable usage and query limits to serve as guardrails against runaway queries and unapproved usage patterns. Furthermore, it often helps to have a systematic way for allocating service costs based on usage of the data vault to different source systems and user groups within your organization.

The following are common cost and resource management requirements for Data Vault implementations at scale:

  • Utilization limits and query resource guardrails
  • Advanced workload management
  • Chargeback capabilities

Amazon Redshift features and capabilities for cost and resource management

In this section, we discuss Amazon Redshift features and capabilities that address those cost and resource management requirements.

Utilization limits and query monitoring rules

Runaway queries and excessive auto scaling are likely to be the two most common runaway patterns observed with data vault implementations at scale.

A Redshift provisioned cluster supports usage limits for features such as Redshift Spectrum, concurrency scaling, and cross-Region data sharing. A concurrency scaling limit specifies the threshold of the total amount of time used by concurrency scaling in 1-minute increments. A limit can be specified for a daily, weekly, or monthly period (using UTC to determine the start and end of the period).

You can also define multiple usage limits for each feature. Each limit can have a different action, such as logging to system tables, alerting via Amazon CloudWatch alarms and optionally Amazon Simple Notification Service (Amazon SNS) subscriptions to that alarm (such as email or text), or disabling the feature outright until the next time period begins (such as the start of the month). When a usage limit threshold is reached, events are also logged to a system table.

Redshift provisioned clusters also support query monitoring rules to define metrics-based performance boundaries for workload management queues and the action that should be taken when a query goes beyond those boundaries. For example, for a queue dedicated to short-running queries, you might create a rule that cancels queries that run for more than 60 seconds. To track poorly designed queries, you might have another rule that logs queries that contain nested loops.

Each query monitoring rule includes up to three conditions, or predicates, and one query action (such as stop, hop, or log). A predicate consists of a metric, a comparison condition (=, <, or >), and a value. If all of the predicates for any rule are met, that rule’s action is triggered. Amazon Redshift evaluates metrics every 10 seconds and if more than one rule is triggered during the same period, Amazon Redshift initiates the most severe action (stop, then hop, then log).

Redshift Serverless also supports usage limits where you can specify the base capacity according to your price-performance requirements. You can also set the maximum RPU (Redshift Processing Units) hours used per day, per week, or per month to keep the cost predictable and specify different actions, such as write to system table, receive an alert, or turn off user queries when the limit is reached. A cross-Region data sharing usage limit is also supported, which limits how much data transferred from the producer Region to the consumer Region that consumers can query.

You can also specify query limits in Redshift Serverless to stop poorly performing queries that exceed the threshold value.

Auto workload management

Not all queries have the same performance profile or priority, and data vault queries are no different. Amazon Redshift workload management (WLM) adapts in real time to the priority, resource allocation, and concurrency settings required to optimally run different data vault queries. These queries could consist of a high number of joins between the hubs, links, and satellites tables; large-scale scans of the satellite tables; or massive aggregations. Amazon Redshift WLM enables you to flexibly manage priorities within workloads so that, for example, short or fast-running queries won’t get stuck in queues behind long-running queries.

You can use automatic WLM to maximize system throughput and use resources effectively. You can enable Amazon Redshift to manage how resources are divided to run concurrent queries with automatic WLM. Automatic WLM manages the resources required to run queries. Amazon Redshift determines how many queries run concurrently and how much memory is allocated to each dispatched query.

Chargeback metadata

Amazon Redshift provides different pricing models to cater to different customer needs. On-demand pricing offers the greatest flexibility, whereas Reserved Instances provide significant discounts for predictable and steady usage scenarios. Redshift Serverless provides a pay-as-you-go model that is ideal for sporadic workloads.

However, with any of these pricing models, Amazon Redshift customers can attribute cost to different users. To start, Amazon Redshift provides itemized billing like many other AWS services in AWS Cost Explorer to attain the overall cost of using Amazon Redshift. Moreover, the cross-group collaboration (data sharing) capability of Amazon Redshift enables a more explicit and structured chargeback model to different teams.

Availability

In the modern data organization, data warehouses are no longer used purely to perform historical analysis in batches overnight with relatively forgiving SLAs, Recovery Time Objectives (RTOs), and Recovery Point Objectives (RPOs). They have become mission-critical systems in their own right that are used for both historical analysis and near-real-time data analysis. Data Vault systems at scale very much fit that mission-critical profile, which makes availability key.

The following are common availability requirements for Data Vault implementations at scale:

  • RTO of near-zero
  • RPO of near-zero
  • Automated failover
  • Advanced backup management
  • Commercial-grade SLA

Amazon Redshift features and capabilities for availability

In this section, we discuss the features and capabilities in Amazon Redshift that address those availability requirements.

Separation of storage and compute

AWS and Amazon Redshift are inherently resilient. With Amazon Redshift, there’s no additional cost for active-passive disaster recovery. Amazon Redshift replicates all of your data within your data warehouse when it is loaded and also continuously backs up your data to Amazon S3. Amazon Redshift always attempts to maintain at least three copies of your data (the original and replica on the compute nodes, and a backup in Amazon S3).

With separation of storage and compute and Amazon S3 as the persistence layer, you can achieve an RPO of near-zero, if not zero itself.

Cluster relocation to another Availability Zone

Amazon Redshift provisioned RA3 clusters support cluster relocation to another Availability Zone in events where cluster operation in the current Availability Zone is not optimal, without any data loss or changes to your application. Cluster relocation is available free of charge; however, relocation might not always be possible if there is a resource constraint in the target Availability Zone.

Multi-AZ deployment

For many customers, the cluster relocation feature is sufficient; however, enterprise data warehouse customers require a low RTO and higher availability to support their business continuity with minimal impact to applications.

Amazon Redshift supports Multi-AZ deployment for provisioned RA3 clusters.

A Redshift Multi-AZ deployment uses compute resources in multiple Availability Zones to scale data warehouse workload processing as well as provide an active-active failover posture. In situations where there is a high level of concurrency, Amazon Redshift will automatically use the resources in both Availability Zones to scale the workload for both read and write requests using active-active processing. In cases where there is a disruption to an entire Availability Zone, Amazon Redshift will continue to process user requests using the compute resources in the sister Availability Zone.

With features such as multi-AZ deployment, you can achieve a low RTO, should there ever be a disruption to the primary Redshift cluster or an entire Availability Zone.

Automated backup

Amazon Redshift automatically takes incremental snapshots that track changes to the data warehouse since the previous automated snapshot. Automated snapshots retain all of the data required to restore a data warehouse from a snapshot. You can create a snapshot schedule to control when automated snapshots are taken, or you can take a manual snapshot any time.

Automated snapshots can be taken as often as once every hour and retained for up to 35 days at no additional charge to the customer. Manual snapshots can be kept indefinitely at standard Amazon S3 rates. Furthermore, automated snapshots can be automatically replicated to another Region and stored there as a disaster recovery site also at no additional charge (with the exception of data transfer charges across Regions) and manual snapshots can also be replicated with standard Amazon S3 rates applying (and data transfer costs).

Amazon Redshift SLA

As a managed service, Amazon Redshift frees you from being the first and only line of defense against disruptions. AWS will use commercially reasonable efforts to make Amazon Redshift available with a monthly uptime percentage for each Multi-AZ Redshift cluster during any monthly billing cycle, of at least 99.99% and for multi-node cluster, at least 99.9%. In the event that Amazon Redshift doesn’t meet the Service Commitment, you will be eligible to receive a Service Credit.

Scalability

One of the major motivations of organizations migrating to the cloud is improved and increased scalability. With Amazon Redshift, Data Vault systems will always have a number of scaling options available to them.

The following are common scalability requirements for Data Vault implementations at scale:

  • Automated and fast-initiating horizontal scaling
  • Robust and performant vertical scaling
  • Data reuse and sharing mechanisms

Amazon Redshift features and capabilities for scalability

In this section, we discuss the features and capabilities in Amazon Redshift that address those scalability requirements.

Horizontal and vertical scaling

Amazon Redshift uses concurrency scaling automatically to support virtually unlimited horizontal scaling of concurrent users and concurrent queries, with consistently fast query performance. Furthermore, concurrency scaling requires no downtime, supports read/write operations, and is typically the most impactful and used scaling option for customers during normal business operations to maintain consistent performance.

With Amazon Redshift provisioned warehouse, as your data warehousing capacity and performance needs to change or grow, you can vertically scale your cluster to make the best use of the computing and storage options that Amazon Redshift provides. Resizing your cluster by changing the node type or number of nodes can typically be achieved in 10–15 minutes. Vertical scaling typically occurs much less frequently in response to persistent and organic growth and is typically performed during a planned maintenance window when the short downtime doesn’t impact business operations.

Explicit horizontal or vertical resize and pause operations can be automated per a schedule (for example, development clusters can be automatically scaled down or paused for the weekends). Note that the storage of paused clusters remains accessible to clusters with which their data was shared.

For resource-intensive workloads that might benefit from a vertical scaling operation vs. concurrency scaling, there are also other best-practice options that avoid downtime, such as deploying the workload onto its own Redshift Serverless warehouse while using data sharing.

Redshift Serverless measures data warehouse capacity in RPUs, which are resources used to handle workloads. You can specify the base data warehouse capacity Amazon Redshift uses to serve queries (ranging from as little as 8 RPUs to as high as 512 RPUs) and change the base capacity at any time.

Data sharing

Amazon Redshift data sharing is a secure and straightforward way to share live data for read purposes across Redshift warehouses within the same or different accounts and Regions. This enables high-performance data access while preserving workload isolation. You can have separate Redshift warehouses, either provisioned or serverless, for different use cases according to your compute requirement and seamlessly share data between them.

Common use cases for data sharing include setting up a central ETL warehouse to share data with many BI warehouses to provide read workload isolation and chargeback, offering data as a service and sharing data with external consumers, multiple business groups within an organization, sharing and collaborating on data to gain differentiated insights, and sharing data between development, test, and production environments.

Reference architecture

The diagram in this section shows one possible reference architecture of a Data Vault 2.0 system implemented with Amazon Redshift.

We suggest using three different Redshift warehouses to run a Data Vault 2.0 model in Amazon Redshift. The data between these data warehouses is shared via Amazon Redshifts data sharing and allows you to consume data from a consumer data warehouse even if the provider data warehouse is inactive.

  • Raw Data Vault – The RDV data warehouse hosts hubs, links, and satellite tables. For large models, you can additionally slice the RDV into additional data warehouses to even better adopt the data warehouse sizing to your workload patterns. Data is ingested via the patterns described in the previous section as batch or high velocity data.
  • Business Data Vault – The BDV data warehouse hosts bridge and point in time (PIT) tables. These tables are computed based on the RDV tables using Amazon Redshift. Materialized or automatic materialized views are straightforward mechanisms to create those.
  • Consumption cluster – This data warehouse contains query-optimized data formats and marts. Users interact with this layer.

If the workload pattern is unknown, we suggest starting with a Redshift Serverless warehouse and learning the workload pattern. You can easily migrate between a serverless and provisioned Redshift cluster at a later stage based on your processing requirements, as discussed in Part 1 of this series.

Best practices building a Data Vault warehouse on AWS

In this section, we cover how the AWS Cloud as a whole plays its role in building an enterprise-grade Data Vault warehouse on Amazon Redshift.

Education

Education is a fundamental success factor. Data Vault is more complex than traditional data modeling methodologies. Before you start the project, make sure everyone understands the principles of Data Vault. Amazon Redshift is designed to be very easy to use, but to ensure the most optimal Data Vault implementation on Amazon Redshift, gaining a good understanding of how Amazon Redshift works is recommended. Start with free resources like reaching out to your AWS account representative to schedule a free Amazon Redshift Immersion Day or train for the AWS Analytics specialty certification.

Automation

Automation is a major benefit of Data Vault. This will increase efficiency and consistency across your data landscape. Most customers focus on the following aspects when automating Data Vault:

  • Automated DDL and DML creation, including modeling tools especially for the raw data vault
  • Automated ingestion pipeline creation
  • Automated metadata and lineage support

Depending on your needs and skills, we typically see three different approaches:

  • DSL – This is a common tool for generating data vault models and flows with Domain Specific Languages (DSL). Popular frameworks for building such DSLs are EMF with Xtext or MPS. This solution provides the most flexibility. You directly build your business vocabulary into the application and generate documentation and business glossary along with the code. This approach requires the most skill and biggest resource investment.
  • Modeling tool – You can build on an existing modeling language like UML 2.0. Many modeling tools come with code generators. Therefore, you don’t need to build your own tool, but these tools are often hard to integrate into modern DevOps pipelines. They also require UML 2.0 knowledge, which raises the bar for non-tech users.
  • Buy – There are a number of different third-party solutions that integrate well into Amazon Redshift and are available via AWS Marketplace.

Whichever approach of the above-mentioned approaches you choose, all three approaches offer multiple benefits. For example, you can take away repetitive tasks from your development team and enforce modeling standards like data types, data quality rules, and naming conventions. To generate the code and deploy it, you can use AWS DevOps services. As part of this process, you save the generated metadata to the AWS Glue Data Catalog, which serves as a central technical metadata catalog. You then deploy the generated code to Amazon Redshift (SQL scripts) and to AWS Glue.

We designed AWS CloudFormation for automation; it’s the AWS-native way of automating infrastructure creation and management. A major use case for infrastructure as code (IaC) is to create new ingestion pipelines for new data sources or add new entities to existing one.

You can also use our new AI coding tool Amazon CodeWhisperer, which helps you quickly write secure code by generating whole line and full function code suggestions in your IDE in real time, based on your natural language comments and surrounding code. For example, CodeWhisperer can automatically take a prompt such as “get new files uploaded in the last 24 hours from the S3 bucket” and suggest appropriate code and unit tests. This can greatly reduce development effort in writing code, for example for ETL pipelines or generating SQL queries, and allow more time for implementing new ideas and writing differentiated code.

Operations

As previously mentioned, one of the benefits of Data Vault is the high level of automation which, in conjunction with serverless technologies, can lower the operating efforts. On the other hand, some industry products come with built-in schedulers or orchestration tools, which might increase operational complexity. By using AWS-native services, you’ll benefit from integrated monitoring options of all AWS services.

Conclusion

In this series, we discussed a number of crucial areas required for implementing a Data Vault 2.0 system at scale, and the Amazon Redshift capabilities and AWS ecosystem that you can use to satisfy those requirements. There are many more Amazon Redshift capabilities and features that will surely come in handy, and we strongly encourage current and prospective customers to reach out to us or other AWS colleagues to delve deeper into Data Vault with Amazon Redshift.


About the Authors

Asser Moustafa is a Principal Analytics Specialist Solutions Architect at AWS based out of Dallas, Texas. He advises customers globally on their Amazon Redshift and data lake architectures, migrations, and visions—at all stages of the data ecosystem lifecycle—starting from the POC stage to actual production deployment and post-production growth.

Philipp Klose is a Global Solutions Architect at AWS based in Munich. He works with enterprise FSI customers and helps them solve business problems by architecting serverless platforms. In this free time, Philipp spends time with his family and enjoys every geek hobby possible.

Saman Irfan is a Specialist Solutions Architect at Amazon Web Services. She focuses on helping customers across various industries build scalable and high-performant analytics solutions. Outside of work, she enjoys spending time with her family, watching TV series, and learning new technologies.

Introducing advanced logging controls for AWS Lambda functions

Post Syndicated from David Boyne original https://aws.amazon.com/blogs/compute/introducing-advanced-logging-controls-for-aws-lambda-functions/

This post is written by Nati Goldberg, Senior Solutions Architect and Shridhar Pandey, Senior Product Manager, AWS Lambda

Today, AWS is launching advanced logging controls for AWS Lambda, giving developers and operators greater control over how function logs are captured, processed, and consumed.

This launch introduces three new capabilities to provide a simplified and enhanced default logging experience on Lambda.

First, you can capture Lambda function logs in JSON structured format without having to use your own logging libraries. JSON structured logs make it easier to search, filter, and analyze large volumes of log entries.

Second, you can control the log level granularity of Lambda function logs without making any code changes, enabling more effective debugging and troubleshooting.

Third, you can also set which Amazon CloudWatch log group Lambda sends logs to, making it easier to aggregate and manage logs at scale.

Overview

Being able to identify and filter relevant log messages is essential to troubleshoot and fix critical issues. To help developers and operators monitor and troubleshoot failures, the Lambda service automatically captures and sends logs to CloudWatch Logs.

Previously, Lambda emitted logs in plaintext format, also known as unstructured log format. This unstructured format could make the logs challenging to query or filter. For example, you had to search and correlate logs manually using well-known string identifiers such as “START”, “END”, “REPORT” or the request id of the function invocation. Without a native way to enrich application logs, you needed custom work to extract data from logs for automated analysis or to build analytics dashboards.

Previously, operators could not control the level of log detail generated by functions. They relied on application development teams to make code changes to emit logs with the required granularity level, such as INFO, DEBUG, or ERROR.

Lambda-based applications often comprise microservices, where a single microservice is composed of multiple single-purpose Lambda functions. Before this launch, Lambda sent logs to a default CloudWatch log group created with the Lambda function with no option to select a log group. Now you can aggregate logs from multiple functions in one place so you can uniformly apply security, governance, and retention policies to your logs.

Capturing Lambda logs in JSON structured format

Lambda now natively supports capturing structured logs in JSON format as a series of key-value pairs, making it easier to search and filter logs more easily.

JSON also enables you to add custom tags and contextual information to logs, enabling automated analysis of large volumes of logs to help understand the function performance. The format adheres to the OpenTelemetry (OTel) Logs Data Model, a popular open-source logging standard, enabling you to use open-source tools to monitor functions.

To set the log format in the Lambda console, select the Configuration tab, choose Monitoring and operations tools on the left pane, then change the log format property:

Currently, Lambda natively supports capturing application logs (logs generated by the function code) and system logs (logs generated by the Lambda service) in JSON structured format.

This is for functions that use non-deprecated versions of Python, Node.js, and Java Lambda managed runtimes, when using Lambda recommended logging methods such as using logging library for Python, console object for Node.js, and LambdaLogger or Log4j for Java.

For other managed runtimes, Lambda currently only supports capturing system logs in JSON structured format. However, you can still capture application logs in JSON structured format for these runtimes by manually configuring logging libraries. See configuring advanced logging controls section in the Lambda Developer Guide to learn more. You can also use Powertools for AWS Lambda to capture logs in JSON structured format.

Changing log format from text to JSON can be a breaking change if you parse logs in a telemetry pipeline. AWS recommends testing any existing telemetry pipelines after switching log format to JSON.

Working with JSON structured format for Node.js Lambda functions

You can use JSON structured format with CloudWatch Embedded Metric Format (EMF) to embed custom metrics alongside JSON structured log messages, and CloudWatch automatically extracts the custom metrics for visualization and alarming. However, to use JSON log format along with EMF libraries for Node.js Lambda functions, you must use the latest version of the EMF client library for Node.js or the latest version of Powertools for AWS Lambda (TypeScript) library.

Configuring log level granularity for Lambda function

You can now filter Lambda logs by log level, such as ERROR, DEBUG, or INFO, without code changes. Simplified log level filtering enables you to choose the required logging granularity level for Lambda functions, without sifting through large volumes of logs to debug errors.

You can specify separate log level filters for application logs (which are logs generated by the function code) and system logs (which are logs generated by the Lambda service, such as START and REPORT log messages). Note that log level controls are only available if the log format of the function is set to JSON.

The Lambda console allows setting both the Application log level and System log level properties:

You can define the granularity level of each log event in your function code. The following statement prints out the event input of the function, emitted as a DEBUG log message:

console.debug(event);

Once configured, log events emitted with a lower log level than the one selected are not published to the function’s CloudWatch log stream. For example, setting the function’s log level to INFO results in DEBUG log events being ignored.

This capability allows you to choose the appropriate amount of logs emitted by functions. For example, you can set a higher log level to improve the signal-to-noise ratio in production logs, or set a lower log level to capture detailed log events for testing or troubleshooting purposes.

Customizing Lambda function’s CloudWatch log group

Previously, you could not specify a custom CloudWatch log group for functions, so you could not stream logs from multiple functions into a shared log group. Also, to set custom retention policy for multiple log groups, you had to create each log group separately using a pre-defined name (for example, /aws/lambda/<function name>).

Now you can select a custom CloudWatch log group to aggregate logs from multiple functions automatically within an application in one place. You can apply security, governance, and retention policies at the application level instead of individually to every function.

To distinguish between logs from different functions in a shared log group, each log stream contains the Lambda function name and version.

You can share the same log group between multiple functions to aggregate logs together. The function’s IAM policy must include the logs:CreateLogStream and logs:PutLogEvents permissions for Lambda to create logs in the specified log group. The Lambda service can optionally create these permissions, when you configure functions in the Lambda console.

You can set the custom log group in the Lambda console by entering the destination log group name. If the entered log group does not exist, Lambda creates it automatically.

Advanced logging controls for Lambda can be configured using Lambda API, AWS Management Console, AWS Command Line Interface (CLI), and infrastructure as code (IaC) tools such as AWS Serverless Application Model (AWS SAM) and AWS CloudFormation.

Example of Lambda advanced logging controls

This section demonstrates how to use the new advanced logging controls for Lambda using AWS SAM to build and deploy the resources in your AWS account.

Overview

The following diagram shows Lambda functions processing newly created objects inside an Amazon S3 bucket, where both functions emit logs into the same CloudWatch log group:

The architecture includes the following steps:

  1. A new object is created inside an S3 bucket.
  2. S3 publishes an event using S3 Event Notifications to Amazon EventBridge.
  3. EventBridge triggers two Lambda functions asynchronously.
  4. Each function processes the object to extract labels and text, using Amazon Rekognition and Amazon Textract.
  5. Both functions then emit logs into the same CloudWatch log group.

This uses AWS SAM to define the Lambda functions and configure the required logging controls. The IAM policy allows the function to create a log stream and emit logs to the selected log group:

DetectLabelsFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: detect-labels/
      Handler: app.lambdaHandler
      Runtime: nodejs18.x
      Policies:
        ...
        - Version: 2012-10-17
          Statement:
            - Sid: CloudWatchLogGroup
              Action: 
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: !GetAtt CloudWatchLogGroup.Arn
              Effect: Allow
      LoggingConfig:
        LogFormat: JSON 
        ApplicationLogLevel: DEBUG 
        SystemLogLevel: INFO 
        LogGroup: !Ref CloudWatchLogGroup 

Deploying the example

To deploy the example:

  1. Clone the GitHub repository and explore the application.
    git clone https://github.com/aws-samples/advanced-logging-controls-lambda/
    
    cd advanced-logging-controls-lambda
  2. Use AWS SAM to build and deploy the resources to your AWS account. This compiles and builds the application using npm, and then populate the template required to deploy the resources:
    sam build
  3. Deploy the solution to your AWS account with a guided deployment, using AWS SAM CLI interactive flow:
    sam deploy --guided
  4. Enter the following values:
    • Stack Name: advanced-logging-controls-lambda
    • Region: your preferred Region (for example, us-east-1)
    • Parameter UploadsBucketName: enter a unique bucket name.
    • Accept the rest of the initial defaults.
  5. To test the application, use the AWS CLI to copy the sample image into the S3 bucket you created.
    aws s3 cp samples/skateboard.jpg s3://example-s3-images-bucket

Explore CloudWatch Logs to view the logs emitted into the log group created, AggregatedLabelsLogGroup:

The DetectLabels Lambda function emits DEBUG log events in JSON format to the log stream. Log events with the same log level from the ExtractText Lambda function are omitted. This is a result of the different application log level settings for each function (DEBUG and INFO).

You can also use CloudWatch Logs Insights to search, filter, and analyze the logs in JSON format using this sample query:

You can see the results:

Conclusion

Advanced logging controls for Lambda give you greater control over logging. Use advanced logging controls to control your Lambda function’s log level and format, allowing you to search, query, and filter logs to troubleshoot issues more effectively.

You can also choose the CloudWatch log group where Lambda sends your logs. This enables you to aggregate logs from multiple functions into a single log group, apply retention, security, governance policies, and easily manage logs at scale.

To get started, specify the required settings in the Logging Configuration for any new or existing Lambda functions.

Advanced logging controls for Lambda are available in all AWS Regions where Lambda is available at no additional cost. Learn more about AWS Lambda Advanced Logging Controls.

For more serverless learning resources, visit Serverless Land.

Use scalable controls for AWS services accessing your resources

Post Syndicated from James Greenwood original https://aws.amazon.com/blogs/security/use-scalable-controls-for-aws-services-accessing-your-resources/

Sometimes you want to configure an AWS service to access your resource in another service. For example, you can configure AWS CloudTrail, a service that monitors account activity across your AWS infrastructure, to write log data to your bucket in Amazon Simple Storage Service (Amazon S3). When you do this, you want assurance that the service will only access your resource on your behalf—you don’t want an untrusted entity to be able to use the service to access your resource. Before today, you could achieve this by using the two AWS Identity and Access Management (IAM) condition keys, aws:SourceAccount and aws:SourceArn. You can use these condition keys to help make sure that a service accesses your resource only on behalf of specific accounts or resources that you trust. However, because these condition keys require you to specify individual accounts and resources, they can be difficult to manage at scale, especially in larger organizations.

Recently, IAM launched two new condition keys that can help you achieve this in a more scalable way that is simpler to manage within your organization:

  • aws:SourceOrgID — use this condition key to make sure that an AWS service can access your resources only when the request originates from a particular organization ID in AWS Organizations.
  • aws:SourceOrgPaths — use this condition key to make sure that an AWS service can access your resources only when the request originates from one or more organizational units (OUs) in your organization.

In this blog post, we describe how you can use the four available condition keys, including the two new ones, to help you control how AWS services access your resources.

Background

Imagine a scenario where you configure an AWS service to access your resource in another service. Let’s say you’re using Amazon CloudWatch to observe resources in your AWS environment, and you create an alarm that activates when certain conditions occur. When the alarm activates, you want it to publish messages to a topic that you create in Amazon Simple Notification Service (Amazon SNS) to generate notifications.

Figure 1 depicts this process.

Figure 1: Amazon CloudWatch publishing messages to an SNS topic

Figure 1: Amazon CloudWatch publishing messages to an SNS topic

In this scenario, there’s a resource-based policy controlling access to your SNS topic. For CloudWatch to publish messages to it, you must configure the policy to allow access by CloudWatch. When you do this, you identify CloudWatch using an AWS service principal, in this case cloudwatch.amazonaws.com.

Cross-service access

This is an example of a common pattern known as cross-service access. With cross-service access, a calling service accesses your resource in a called service, and a resource-based policy attached to your resource grants access to the calling service. The calling service is identified using an AWS service principal in the form <SERVICE-NAME>.amazonaws.com, and it accesses your resource on behalf of an originating resource, such as a CloudWatch alarm.

Figure 2 shows cross-service access.

Figure 2: Cross-service access

Figure 2: Cross-service access

When you configure cross-service access, you want to make sure that the calling service will access your resource only on your behalf. That means you want the originating resource to be controlled by someone whom you trust. If an untrusted entity creates their own CloudWatch alarm in their AWS environment, for example, then their alarm should not be able to publish messages to your SNS topic.

If an untrusted entity could use a calling service to access your resource on their behalf, it would be an example of what’s known as the confused deputy problem. The confused deputy problem is a security issue in which an entity that doesn’t have permission to perform an action coerces a more privileged entity (in this case, a calling service) to perform the action instead.

Use condition keys to help prevent cross-service confused deputy issues

AWS provides global condition keys to help you prevent cross-service confused deputy issues. You can use these condition keys to control how AWS services access your resources.

Before today, you could use the aws:SourceAccount or aws:SourceArn condition keys to make sure that a calling service accesses your resource only when the request originates from a specific account (with aws:SourceAccount) or a specific originating resource (with aws:SourceArn). However, there are situations where you might want to allow multiple resources or accounts to use a calling service to access your resource. For example, you might want to create many VPC flow logs in an organization that publish to a central S3 bucket. To achieve this using the aws:SourceAccount or aws:SourceArn condition keys, you must enumerate all the originating accounts or resources individually in your resource-based policies. This can be difficult to manage, especially in large organizations, and can potentially cause your resource-based policy documents to reach size limits.

Now, you can use the new aws:SourceOrgID or aws:SourceOrgPaths condition keys to make sure that a calling service accesses your resource only when the request originates from a specific organization (with aws:SourceOrgID) or a specific organizational unit (with aws:SourceOrgPaths). This helps avoid the need to update policies when accounts are added or removed, reduces the size of policy documents, and makes it simpler to create and review policy statements.

The following table summarizes the four condition keys that you can use to help prevent cross-service confused deputy issues. These keys work in a similar way, but with different levels of granularity.

Use case Condition key Value Allowed operators Single/multi valued Example value
Allow a calling service to access your resource only on behalf of an organization that you trust. aws:SourceOrgID AWS organization ID of the resource making a cross-service access request String operators Single-valued key o-a1b2c3d4e5
Allow a calling service to access your resource only on behalf of an organizational unit (OU) that you trust. aws:SourceOrgPaths Organization entity paths of the resource making a cross-service access request Set operators and string operators Multivalued key o-a1b2c3d4e5/r-ab12/ou-ab12-11111111/ou-ab12-22222222/
Allow a calling service to access your resource only on behalf of an account that you trust. aws:SourceAccount AWS account ID of the resource making a cross-service access request String operators Single-valued key 111122223333
Allow a calling service to access your resource only on behalf of a resource that you trust. aws:SourceArn Amazon Resource Name (ARN) of the resource making a cross- service access request ARN operators (recommended) or string operators Single-valued key arn:aws:cloudwatch:eu-west-1:111122223333:alarm:myalarm

When to use the condition keys

AWS recommends that you use these condition keys in any resource-based policy statements that allow access by an AWS service, except where the relevant condition key is not yet supported by the service. To find out whether a condition key is supported by a particular service, see AWS global condition context keys in the AWS Identity and Access Management User Guide.

Note: Only use these condition keys in resource-based policies that allow access by an AWS service. Don’t use them in other use cases, including identity-based policies and service control policies (SCPs), where these condition keys won’t be populated.

Use condition keys for defense in depth

AWS services use a variety of mechanisms to help prevent cross-service confused deputy issues, and the details vary by service. For example, where a calling service accesses an S3 bucket, some services use S3 prefixes to help prevent confused deputy issues. For more information, see the relevant service documentation.

Where supported by the service, AWS recommends that you use the condition keys we describe in this post regardless of whether the service has another mechanism in place to help prevent cross-service confused deputy issues. This helps to make your intentions explicit, provide defense in depth, and guard against misconfigurations.

Example use cases

Let’s walk through some example use cases to learn how to use these condition keys in practice.

First, imagine you’re using Amazon Virtual Private Cloud (Amazon VPC) to manage logically isolated virtual networks. In Amazon VPC, you can configure flow logs, which capture information about your network traffic. Let’s say you want a flow log to write data into an S3 bucket for later analysis. This process is depicted in Figure 3.

Figure 3: Amazon VPC writing flow logs to an S3 bucket

Figure 3: Amazon VPC writing flow logs to an S3 bucket

This constitutes another cross-service access scenario. In this case, Amazon VPC is the calling service, Amazon S3 is the called service, the VPC flow log is the originating resource, and the S3 bucket is your resource in the called service.

To allow access, the resource-based policy for your S3 bucket (known as a bucket policy) must allow Amazon VPC to put objects there. The Principal element in this policy specifies the AWS service principal of the service that will access the resource, which for VPC flow logs is delivery.logs.amazonaws.com.

Initial policy without confused deputy prevention

The following is an initial version of the bucket policy that allows Amazon VPC to put objects in the bucket but doesn’t yet provide confused deputy prevention. We’re showing this policy for illustration purposes; don’t use it in its current form.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PARTIAL-EXAMPLE-DO-NOT-USE",
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<DOC-EXAMPLE-BUCKET>/*"
        }
    ]
}

Note: For simplicity, we only show one of the policy statements that you need to allow VPC flow logs to write to a bucket. In a real-life bucket policy for flow logs, you need two policy statements: one allowing actions on the bucket, and one allowing actions on the bucket contents. These are described in Publish flow logs to Amazon S3. Both policy statements work in the same way with respect to confused deputy prevention.

This policy statement allows Amazon VPC to put objects in the bucket. However, it allows Amazon VPC to do that on behalf of any flow log in any account. There’s nothing in the policy to tell Amazon VPC that it should access this bucket only if the flow log belongs to a specific organization, OU, account, or resource that you trust.

Let’s now update the policy to help prevent cross-service confused deputy issues. For the rest of this post, the remaining policy samples provide confused deputy protection, but at different levels of granularity.

Specify a trusted organization

Continuing with the previous example, imagine that you now have an organization in AWS Organizations, and you want to create VPC flow logs in various accounts within your organization that publish to a central S3 bucket. You want Amazon VPC to put objects in the bucket only if the request originates from a flow log that resides in your organization.

You can achieve this by using the new aws:SourceOrgID condition key. In a cross-service access scenario, this condition key evaluates to the ID of the organization that the request came from. You can use this condition key in the Condition element of a resource-based policy to allow actions only if aws:SourceOrgID matches the ID of a specific organization, as shown in the following example. In your own policy, make sure to replace <DOC-EXAMPLE-BUCKET> and <MY-ORGANIZATION-ID> with your own information.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VPCLogsDeliveryWrite",
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<DOC-EXAMPLE-BUCKET>/*",
            "Condition": {
                "StringEquals": {
                    "aws:SourceOrgID": "<MY-ORGANIZATION-ID>"
                }
            }
        }
    ]
}

The revised policy states that Amazon VPC can put objects in the bucket only if the request originates from a flow log in your organization. Now, if someone creates a flow log outside your organization and configures it to access your bucket, they will get an access denied error.

You can use aws:SourceOrgID in this way to allow a calling service to access your resource only if the request originates from a specific organization, as shown in Figure 4.

Figure 4: Specify a trusted organization using aws:SourceOrgID

Figure 4: Specify a trusted organization using aws:SourceOrgID

Specify a trusted OU

What if you don’t want to trust your entire organization, but only part of it? Let’s consider a different scenario. Imagine that you want to send messages from Amazon SNS into a queue in Amazon Simple Queue Service (Amazon SQS) so they can be processed by consumers. This is depicted in Figure 5.

Figure 5: Amazon SNS sending messages to an SQS queue

Figure 5: Amazon SNS sending messages to an SQS queue

Now imagine that you want your SQS queue to receive messages only if they originate from an SNS topic that resides in a specific organizational unit (OU) in your organization. For example, you might want to allow messages only if they originate from a production OU that is subject to change control.

You can achieve this by using the new aws:SourceOrgPaths condition key. As before, you use this condition key in a resource-based policy attached to your resource. In a cross-service access scenario, this condition key evaluates to the AWS Organizations entity path that the request came from. An entity path is a text representation of an entity within an organization.

You build an entity path for an OU by using the IDs of the organization, root, and all OUs in the path down to and including the OU. For example, consider the organizational structure shown in Figure 6.

Figure 6: Example organization structure

Figure 6: Example organization structure

In this example, you can specify the Prod OU by using the following entity path:

o-a1b2c3d4e5/r-ab12/ou-ab12-11111111/ou-ab12-22222222/

For more information about how to construct an entity path, see Understand the AWS Organizations entity path.

Let’s now match the aws:SourceOrgPaths condition key against a specific entity path in the Condition element of a resource-based policy for an SQS queue. In your own policy, make sure to replace <MY-QUEUE-ARN> and <MY-ENTITY-PATH> with your own information.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow-SNS-SendMessage",
            "Effect": "Allow",
            "Principal": {
                "Service": "sns.amazonaws.com"
            },
            "Action": "sqs:SendMessage",
            "Resource": "<MY-QUEUE-ARN>",
            "Condition": {
                "Null": {
                    "aws:SourceOrgPaths": "false"
                },
                "ForAllValues:StringEquals": {
                    "aws:SourceOrgPaths": "<MY-ENTITY-PATH>"
                }
            }
        }
    ]
}

Note: aws:SourceOrgPaths is a multivalued condition key, which means it’s capable of having multiple values in the request context. At the time of writing, it contains a single entity path if the request originates from an account in an organization, and a null value if the request originates from an account that’s not in an organization. Because this key is multivalued, you need to use both a set operator and a string operator to compare values.

In this policy, there are two conditions in the Condition block. The first uses the Null condition operator and compares with a false value to confirm that the condition key’s value is not null. The second uses set operator ForAllValues, which returns true if every condition key value in the request matches at least one value in your policy condition, and string operator StringEquals, which requires an exact match with a value specified in your policy condition.

Note: The reason for the null check is that set operator ForAllValues returns true when a condition key resolves to null. With an Allow effect and the null check in place, access is denied if the request originates from an account that’s not in an organization.

With this policy applied to your SQS queue, Amazon SNS can send messages to your queue only if the message came from an SNS topic in a specific OU.

You can use aws:SourceOrgPaths in this way to allow a calling service to access your resource only if the request originates from a specific organizational unit, as shown in Figure 7.

Figure 7: Specify a trusted OU using aws:SourceOrgPaths

Figure 7: Specify a trusted OU using aws:SourceOrgPaths

Specify a trusted OU and its children

In the previous example, we specified a trusted OU, but that didn’t include its child OUs. What if you want to include its children as well?

You can achieve this by replacing the string operator StringEquals with StringLike. This allows you to use wildcards in the entity path. Using the organization structure from the previous example, the following Condition evaluates to true only if the condition key value is not null and the request originates from the Prod OU or any of its child OUs.

"Condition": {
    "Null": {
        "aws:SourceOrgPaths": "false"
    },
    "ForAllValues:StringLike": {
        "aws:SourceOrgPaths": "o-a1b2c3d4e5/r-ab12/ou-ab12-11111111/ou-ab12-22222222/*"
    }
}

Specify a trusted account

If you want to be more granular, you can allow a service to access your resource only if the request originates from a specific account. You can achieve this by using the aws:SourceAccount condition key. In a cross-service access scenario, this condition key evaluates to the ID of the account that the request came from. 

The following Condition evaluates to true only if the request originates from the account that you specify in the policy. In your own policy, make sure to replace <MY-ACCOUNT-ID> with your own information.

"Condition": {
    "StringEquals": {
        "aws:SourceAccount": "<MY-ACCOUNT-ID>"
    }
}

You can use this condition element within a resource-based policy to allow a calling service to access your resource only if the request originates from a specific account, as shown in Figure 8.

Figure 8: Specify a trusted account using aws:SourceAccount

Figure 8: Specify a trusted account using aws:SourceAccount

Specify a trusted resource

If you want to be even more granular, you can allow a service to access your resource only if the request originates from a specific resource. For example, you can allow Amazon SNS to send messages to your SQS queue only if the request originates from a specific topic within Amazon SNS.

You can achieve this by using the aws:SourceArn condition key. In a cross-service access scenario, this condition key evaluates to the Amazon Resource Name (ARN) of the originating resource. This provides the most granular form of cross-service confused deputy prevention.

The following Condition evaluates to true only if the request originates from the resource that you specify in the policy. In your own policy, make sure to replace <MY-RESOURCE-ARN> with your own information.

"Condition": {
    "ArnEquals": {
        "aws:SourceArn": "<MY-RESOURCE-ARN>"
    }
}

Note: AWS recommends that you use an ARN operator rather than a string operator when comparing ARNs. This example uses ArnEquals to match the condition key value against the ARN specified in the policy.

You can use this condition element within a resource-based policy to allow a calling service to access your resource only if the request comes from a specific originating resource, as shown in Figure 9.

Figure 9: Specify a trusted resource using aws:SourceArn

Figure 9: Specify a trusted resource using aws:SourceArn

Specify multiple trusted resources, accounts, OUs, or organizations

The four condition keys allow you to specify multiple trusted entities by matching against an array of values. This allows you to specify multiple trusted resources, accounts, OUs, or organizations in your policies.

Conclusion

In this post, you learned about cross-service access, in which an AWS service communicates with another AWS service to access your resource. You saw that it’s important to make sure that such services access your resources only on your behalf in order to help avoid cross-service confused deputy issues.

We showed you how to help prevent cross-service confused deputy issues by using two new condition keys aws:SourceOrgID and aws:SourceOrgPaths, as well as the other available condition keys aws:SourceAccount and aws:SourceArn. You learned that you should use these condition keys in any resource-based policy statements that allow access by an AWS service, if the condition key is supported by the service. This helps make sure that a calling service can access your resource only when the request originates from a specific organization, OU, account, or resource that you trust.

If you have feedback about this post, submit comments in the Comments section below. If you have questions about this post, start a new thread on AWS IAM re:Post or contact AWS Support.

Want more AWS Security news? Follow us on Twitter.

Author

James Greenwood

James is a Principal Security Solutions Architect who helps AWS Financial Services customers meet their security and compliance objectives in the AWS Cloud. James has a background in identity and access management, authentication, credential management, and data protection with more than 20 years of experience in the financial services industry.

Sophia Yang

Sophia Yang

Sophia is a Senior Product Manager on the AWS Identity and Access Management (IAM) service. She is passionate about enabling customers to build and innovate in AWS in a secure manner.

New – Long-Form voices for Amazon Polly

Post Syndicated from Jeff Barr original https://aws.amazon.com/blogs/aws/new-long-form-voices-for-amazon-polly/

We are launching three new voices for Polly. Powered by a new long-form engine, the voices are natural and expressive, with appropriate pauses, emphasis, and tone.

New Voices
The new long-form voices are perfect for blog posts, news articles, training videos, and marketing content. The underlying Machine Learning model extracts meaning from the text, learning about speech segments, prosody (the pattern of rhythm and pauses), intonation, and other aspects of expressive speech, allowing the synthesized audio to express emotions, especially in dialogs. The new long-form engine uses a deep learning text-to-speech (TTS) model trained to acquire a contextual understanding of the text that allows it to express prosody in an appropriate way. This allows the intention of the story to drive the vocal performance and create the correct emphasis, pauses, and tones of a realistic human voice.

Here are the new voices:

Name Locale Gender Language Sample
Danielle en_US Female English (US)
Gregory en_US Male English (US)
Ruth en_US Female English (US)

Using the New Voices
You can access the new voices using the AWS Management Console, AWS Command Line Interface (AWS CLI), or the AWS SDKs. Using the CLI, I start by listing the voices that use the new long-form engine:

$ aws --region us-east-1 polly describe-voices --output json \
  | jq -r '.Voices[] | select(.SupportedEngines | index("long-form")) | .Name'
Danielle
Gregory
Ruth

I can pick one, or I can try all of them:

for v in `aws polly describe-voices --output json \
          | jq -r '.Voices[] | select(.SupportedEngines | index("long-form")) | .Name'`; do
    Text="Hello my name is $v and I can read blog posts, articles, \
and other long-form content for you. I am the best\!"
    aws polly synthesize-speech --output-format 'mp3' \
    --text "$Text" --voice-id $v $v.mp3 --engine long-form; \
    aws s3 cp $v.mp3 s3://jbarr-voices; \
done

My shell script had a small quoting bug, but the resulting audio was too funny not to include!

Programmatically, you can reproduce my example by writing code that calls the DescribeVoices and SynthesizeSpeech functions.

Things to Know
Here are some interesting things that you should know about the new voices:

Pricing – Long-form voices are priced at $100 per million characters or Speech Marks requests. Check out the Amazon Polly Pricing page to learn more.

Engines & Voices – Some of the voices that I listed above can be used with more than one engine. For example, the Danielle voice can be used with the new long-form engine and the existing neural engine.

Regions – The new engine and voices are available in the US East (N. Virginia) Region.

Check out the new voices, build something awesome, and let me know what you think!

— Jeff;

It’s About Time: Microsecond-Accurate Clocks on Amazon EC2 Instances

Post Syndicated from Chris Munns original https://aws.amazon.com/blogs/compute/its-about-time-microsecond-accurate-clocks-on-amazon-ec2-instances/

This post is written by Josh Levinson, AWS Principal Product Manager and Julien Ridoux, AWS Principal Software Engineer

Today, we announced that we improved the Amazon Time Sync Service to microsecond-level clock accuracy on supported Amazon EC2 instances. This new capability adds a local reference clock to your EC2 instance and is designed to deliver clock accuracy in the low double-digit microsecond range within your instance’s guest OS software. This post shows you how to connect to the improved clocks on your EC2 instances. This post also demonstrates how you can measure your clock accuracy and easily generate and compare timestamps from your EC2 instances with ClockBound, an open source daemon and library.

In general, it’s hard to achieve high-fidelity clock synchronization due to hardware limitations and network variability. While customers have depended on the Amazon Time Sync Service to provide one millisecond clock accuracy, workloads that need microsecond-range accuracy, such as financial trading and broadcasting, required customers to maintain their own time infrastructure, which is a significant operational burden, and expensive. Other clock-sensitive applications that run on the cloud, including distributed databases and storage, have to incorporate message exchange delays with wait periods, data locks, or transaction journaling to maintain consistency at scale.

With global and reliable microsecond-range clock accuracy, you can now migrate and modernize your most time-sensitive applications in the cloud and retire your burdensome on-premises time infrastructure. You can also simplify your applications and increase their throughput by leveraging the high-accuracy timestamps to determine the ordering of events and transactions on workloads across instances, Availability Zones, and Regions. Additionally, you can audit the improved Amazon Time Sync Service to measure and monitor the expected microsecond-range accuracy.

New improvements to Amazon Time Sync Service

The new local clock source can be accessed over the existing Amazon Time Sync Service’s Network Time Protocol (NTP) IPv4 and IPv6 endpoints, or by configuring a new Precision Time Protocol (PTP) reference clock device, to get the best accuracy possible. It’s important to note that both NTP and the new PTP Hardware Clock (PHC) device share the same highly accurate source of time. The new PHC device is part of the AWS Nitro System, so it is directly accessible on supported bare metal and virtualized Amazon EC2 instances without using any customer resources.

A quick note about Leap Seconds

Leap seconds, introduced in 1972, are occasional one-second adjustments to UTC time to factor in irregularities in Earth’s rotation to UTC time in order to accommodate differences between International Atomic Time (TAI) and solar time (Ut1). To manage leap seconds on behalf of customers, we designed leap second smearing within the Amazon Time Sync Service (details on smearing time in “Look Before You Leap”).

Leap seconds are going away, and we are in full support of the decision made at the 27th General Conference on Weights and Measures to abandon leap seconds by or before 2035.

To support this transition, we still plan on smearing time when accessing the Amazon Time Sync Service over the local NTP connection or our Public NTP pools (time.aws.com). The new PHC device, however, will not provide a smeared time option. In the event of a leap seconds, PHC would add the leap seconds following UTC standards. Leap smeared and leap second time sources are the same in most cases. But, since they differ during a leap second event, we do not recommend mixing smeared and non-smeared time sources in your time client configuration during a leap second event.

Connect using NTP (automatic for most customers)

You can connect to the new, microsecond-accurate clocks over NTP the same way you use the Amazon Time Sync Service today at the 169.254.169.123 IPv4 address or the fd00:ec2::123 IPv6 address. This is already the default configuration on all Amazon AMIs and many partner AMIs, including RHEL, Ubuntu, and SUSE. You can verify this connection in your NTP daemon. The below example, using the chrony daemon, verifies that chrony is using the 169.254.169.123 IPv4 address of the Amazon Time Sync Service to synchronize the time:

[ec2-user@ ~]$ chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^- pacific.latt.net              3  10   377    69  +5630us[+5632us] +/-   90ms
^- edge-lax.txryan.com           2   8   377   224   -691us[ -689us] +/-   33ms
^* 169.254.169.123               1   4   377     2  -4487ns[-5914ns] +/-   85us
^- blotch.image1tech.net         2   9   377   327  -1710us[-1720us] +/-   64ms
^- 44.190.40.123                 2   9   377   161  +3057us[+3060us] +/-   84ms

The 169.254.169.123 IPv4 address of the Amazon Time Sync Service is designated with a *, showing it is the source of synchronization on this instance. See the EC2 User Guide for more details on configuring the Amazon Time Sync Service if it is not already configured by default.

Connect using the PTP Hardware Clock

First, you need to install the latest Elastic Network Adapter (ENA) driver. This driver will allow you to connect directly to the PHC. Connect to your instance and install the Linux kernel driver for Elastic Network Adapter (ENA) version 2.10.0 or later. For the installation instructions, see Linux kernel driver for Elastic Network Adapter (ENA) family on GitHub. To enable PTP support in the driver follow the instructions in the section “PTP Hardware Clock (PHC)“.

Once the driver is installed, you need to configure your NTP daemon to connect to the PHC. Below is an example on how to change the configuration in chrony by adding the PHC to your chrony configuration file. Then restart chrony for the change to take place:

[ec2-user ~]$ sudo sh -c 'echo "refclock PHC /dev/ptp0 poll 0 delay 0.000010 prefer" >> /etc/chrony.conf'
[ec2-user ~]$ sudo systemctl restart chronyd

This example uses a +/-5 microsecond range in receiving the reference signal from the PHC. These 10 microseconds are needed to account for operating system latency.

After changing your configuration, you can validate your daemon is correctly syncing to the PHC. Below is an example of output from the chronyc command. An asterisk will appear next to the PHC0 source indicating that you are now syncing to the PHC:

[ec2-user@ ~]$ chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
=============================================================================
#* PHC0                           0   0   377     1   +18ns[  +20ns] +/- 5032ns

The PHC0 device of the Amazon Time Sync Service is designated with a *, showing it is the source of synchronization on this instance

Your chrony tracking information will also show that you are syncing to the PHC:

[ec2-user@ ~]$ chronyc tracking
Reference ID    : 50484330 (PHC0)
Stratum         : 1
Ref time (UTC)  : Mon Nov 13 18:43:09 2023
System time     : 0.000000004 seconds fast of NTP time
Last offset     : -0.000000010 seconds
RMS offset      : 0.000000012 seconds
Frequency       : 7.094 ppm fast
Residual freq   : -0.000 ppm
Skew            : 0.004 ppm
Root delay      : 0.000010000 seconds
Root dispersion : 0.000001912 seconds
Update interval : 1.0 seconds
Leap status     : Normal

See the EC2 User Guide for more details on configuring the PHC.

Measuring your clock accuracy

Clock accuracy is a measure of clock error, typically defined as the offset to UTC. This clock error is the difference between the observed time on the computer and the reference time (also known as true time). If your instance is configured to use the Amazon Time Sync Service where the microsecond-accurate enhancement is available, you will typically see a clock error bound of under 100us using the NTP connection. When configured and synchronized correctly with the new PHC connection, you will typically see a clock error bound of under 40us.

We previously published a blog on measuring and monitoring clock accuracy over NTP, which still applies to the improved NTP connection.

If you are connected to the PHC, your time daemon, such as chronyd, will underestimate the clock error bound. This is because inherently, a PTP hardware clock device in Linux does not pass any “error bound” information to chrony, the way the NTP would. As a result, your clock synchronization daemon assumes the clock itself is accurate to UTC and thus has an “error bound” of 0. To get around this issue, the Nitro System calculates the error bound of the PTP Hardware Clock itself, and exposes it to your EC2 instance over the ENA driver sysfs filesystem. You can read this directly as a value in nanoseconds with the command cat /sys/devices/pci0000:00/0000:00:05.0/phc_error_bound. To get your clock error bound at some instant, you would need to add the clock error bound from chrony or ClockBound at the time that chronyd polls the PTP Hardware Clock and add it to this phc_error_bound value.

Below is how you would calculate the clock error incorporating the PHC clock error to get your true clock error bound:

CLOCK ERROR BOUND = SYSTEM TIME + (.5 * ROOT DELAY) + ROOTDISPERSION + PHC Error Bound

For the values in the example:

PHC Error Bound = cat /sys/devices/pci0000:00/0000:00:05.0/phc_error_bound

The System Time, Root Delay, and Root Dispersion are values taken from the chrony tracking information.

ClockBound

However accurate, a clock is never perfect. Instead of providing an estimate of the clock error, ClockBound provides a reliable confidence interval by automatically calculating the clock accuracy, using the calculations in which the reference time (true time) does exist. The open source ClockBound daemon provides a convenient way to retrieve this confidence interval, and work is continuing to make it easier to integrate into high performance workloads.

Conclusion

The Amazon Time Sync Service’s new microsecond-accurate clocks can be leveraged to migrate and modernize your most clock-sensitive applications in the cloud. In this post, we showed you how to can connect to the improved clocks on supported Amazon EC2 instances, how to measure your clock accuracy, and how to easily generate and compare timestamps from your Amazon EC2 instances with ClockBound. Launch a supported instance and get started today to build using this new capability.

To learn more about the Amazon Time Sync Service, see the EC2 UserGuide for Linux and Windows.

If you have questions about this post, start a new thread on the AWS Compute re:Post or contact AWS Support.

Hear about the Amazon Time Sync Service at re:Invent

We will speak in more detail about the Amazon Time Sync Service during re:invent 2023. Look for Session ID CMP220 in the AWS re:Invent session catalog to register.

Introducing advanced session audit capabilities in Cloudflare One

Post Syndicated from Kenny Johnson original http://blog.cloudflare.com/introducing-advanced-session-audit-capabilities-in-cloudflare-one/


The basis of Zero Trust is defining granular controls and authorization policies per application, user, and device. Having a system with a sufficient level of granularity to do this is crucial to meet both regulatory and security requirements. But there is a potential downside to so many controls: in order to troubleshoot user issues, an administrator has to consider a complex combination of variables across applications, user identity, and device information, which may require painstakingly sifting through logs.

We think there’s a better way — which is why, starting today, administrators can easily audit all active user sessions and associated data used by their Cloudflare One policies. This enables the best of both worlds: extremely granular controls, while maintaining an improved ability to troubleshoot and diagnose Zero Trust deployments in a single, simple control panel. Information that previously lived in a user’s browser or changed dynamically is now available to administrators without the need to bother an end user or dig into logs.

A quick primer on application authentication and authorization

Authentication and Authorization are the two components that a Zero Trust policy evaluates before allowing a user access to a resource.

Authentication is the process of verifying the identity of a user, device, or system. Common methods of authentication include entering usernames and passwords, presenting a digital certificate, or even biometrics like a fingerprint or face scan. Multi-factor authentication (MFA) requires two or more separate methods of authentication for enhanced security, like a hardware key in combination with a password.

Authorization is the process of granting or denying access to specific resources or permissions once an entity has been successfully authenticated. It defines what the authenticated entity can and cannot do within the system.

Application authentication/authorization mechanisms

Web applications, which we’ll focus on, generally use HTTP cookies to handle both authentication and authorization.

Authentication:

  1. Login: When a user logs into a web application by entering their username and password, the application verifies these credentials against its database or in an Identity Provider (IdP). Additional forms of authentication may also be applied to achieve multiple factors of authentication. If they match, the server or external security service (e.g., Cloudflare Access) considers the user authenticated.
  2. Cookie/Token Creation: The server then creates a session for the user in the form of a cookie or JSON Web Token. The cookie is valid for a period of time until the user has to reauthenticate.
  3. Sending and Storing Cookies: The server sends a response back to the user’s browser which includes the session ID and other identifying information about the user in the cookie. The browser then stores this cookie. This cookie is used to recognize the user in their subsequent requests.

Authorization:

  1. Subsequent Requests: For all subsequent requests to the web application, the user’s browser automatically includes the cookie (with the session ID and other identifying information) in the request.
  2. Server-side Verification: The server gets the user data from the cookie and checks if the session is valid. If it’s valid, the server also retrieves the user’s details and their access permissions associated with that session ID.
  3. Authorization Decision: Based on the user’s access permissions, the server decides whether the user is authorized to perform the requested operation or access the requested resource.

This way, the user stays authenticated (and their authorization can be checked) for all subsequent requests after logging in, until the session expires, or they log out.

In modern web applications, this session state is most commonly stored in the form of a JSON Web Token (JWT).

Debugging JWT based authentication

JWTs are used in many modern web applications, and Zero Trust Network Access (ZTNA) solutions like Cloudflare Access, for authentication and authorization. A JWT includes a payload that encodes information about the user and possibly other data, and it’s signed by the server to prevent tampering. JWTs are often used in a stateless manner, meaning the server doesn’t keep a copy of each JWT—it simply verifies and decodes them as they come in with requests. The stateless nature of JWTs means that you do not have to rely on a central system to handle user session management which avoids creating scalability issues as the number of users accessing a system increases.

However, this stateless nature of JWTs makes debugging JWT-based authentication tricky without getting the specific JWT from a user. Here’s why:

1. Token Specificity: Each JWT is specific to a user and a session. It contains information (claims) about the user, the issuing authority, the token’s issuing time, expiration time, and possibly other data. Therefore, to debug a problem, you often need the exact JWT that’s causing the issue.

2. No Server-side Records: Since JWTs are stateless, the server does not store sessions by default. It can’t look up past tokens or their associated state, unless it’s been specifically designed to log them, which is usually not the case due to privacy and data minimization considerations.

3. Transient Issues: Problems with JWTs can be transient—they might relate to the specific moment the token was used. For instance, if a token was expired when a user tried to use it, you’d need that specific token to debug the issue.

4. Privacy and Security: JWTs can contain sensitive information, so they should be handled with care. Getting a JWT from a user might expose their personal information or security credentials to whoever is debugging the issue. In addition, if a user sends their JWT through an insecure channel to a developer or an IT help desk, it could be intercepted (Cloudflare recently released a free HAR Sanitizer to help mitigate this concern).

These factors make it difficult to troubleshoot issues with JWT based authentication without having the specific token in question.

A better way to debug identity issues

We set out to build a better way to debug issues related to a user’s identity in Cloudflare Zero Trust without sharing JWTs or HAR files back and forth. Administrators can now view a user’s Registry Identity (used for Gateway policies) and all active Access sessions.

This session information includes the full identity evaluated by Zero Trust including IdP claims, device posture information, network context and more. We were able to build this feature without any additional load on Access’ authentication logic by leveraging Cloudflare Workers KV. At the time a user authenticates with Access, their associated identity is immediately saved into a Key/Value pair in Workers KV. This all occurs within the context of the user’s authentication event which means there is minimal latency impact or reliance on an external service.

This feature is available to all customers across all Zero Trust plans. If you would like to get started with Cloudflare Zero Trust, sign up for a free account for up to 50 users, today! Or, collaborate with Cloudflare experts to discuss SSE or SASE for your organization and tackle your Zero Trust use cases one step at a time.

The collective thoughts of the interwebz